<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>事件 | Evan&#39;s blog</title>
    <meta name="generator" content="VuePress 1.9.5">
    <link rel="icon" href="/blog/img/favicon.ico">
    <meta name="description" content="web前端技术博客,专注web前端学习与总结。JavaScript,js,ES6,TypeScript,vue,React,python,css3,html5,Node,git,github等技术文章。">
    <meta name="keywords" content="前端博客,个人技术博客,前端,前端开发,前端框架,web前端,前端面试题,技术文档,学习,面试,JavaScript,js,ES6,TypeScript,vue,python,css3,html5,Node,git,github,markdown">
    <meta name="baidu-site-verification" content="7F55weZDDc">
    <meta name="theme-color" content="#11a8cd">
    
    <link rel="preload" href="/blog/assets/css/0.styles.5cae76fb.css" as="style"><link rel="preload" href="/blog/assets/js/app.aaf1b95a.js" as="script"><link rel="preload" href="/blog/assets/js/2.4e88da26.js" as="script"><link rel="preload" href="/blog/assets/js/137.962a7287.js" as="script"><link rel="prefetch" href="/blog/assets/js/10.77cd5446.js"><link rel="prefetch" href="/blog/assets/js/100.a4b7c22a.js"><link rel="prefetch" href="/blog/assets/js/101.f10a486b.js"><link rel="prefetch" href="/blog/assets/js/102.c6fb27ad.js"><link rel="prefetch" href="/blog/assets/js/103.6544c57a.js"><link rel="prefetch" href="/blog/assets/js/104.6da84eb0.js"><link rel="prefetch" href="/blog/assets/js/105.e98afb5b.js"><link rel="prefetch" href="/blog/assets/js/106.00c6a618.js"><link rel="prefetch" href="/blog/assets/js/107.3e384ab5.js"><link rel="prefetch" href="/blog/assets/js/108.cc8462f3.js"><link rel="prefetch" href="/blog/assets/js/109.efac7118.js"><link rel="prefetch" href="/blog/assets/js/11.0b77905f.js"><link rel="prefetch" href="/blog/assets/js/110.bfd96a59.js"><link rel="prefetch" href="/blog/assets/js/111.d67fb86c.js"><link rel="prefetch" href="/blog/assets/js/112.9ecfc68a.js"><link rel="prefetch" href="/blog/assets/js/113.dd57f9de.js"><link rel="prefetch" href="/blog/assets/js/114.a12ac3b9.js"><link rel="prefetch" href="/blog/assets/js/115.856e382b.js"><link rel="prefetch" href="/blog/assets/js/116.941afac4.js"><link rel="prefetch" href="/blog/assets/js/117.df53da43.js"><link rel="prefetch" href="/blog/assets/js/118.906f3d41.js"><link rel="prefetch" href="/blog/assets/js/119.33bd4cde.js"><link rel="prefetch" href="/blog/assets/js/12.6a1ae269.js"><link rel="prefetch" href="/blog/assets/js/120.c7d90a2a.js"><link rel="prefetch" href="/blog/assets/js/121.e9a583b9.js"><link rel="prefetch" href="/blog/assets/js/122.d2edbcb6.js"><link rel="prefetch" href="/blog/assets/js/123.1a632657.js"><link rel="prefetch" href="/blog/assets/js/124.2a2decb0.js"><link rel="prefetch" href="/blog/assets/js/125.f9344214.js"><link rel="prefetch" href="/blog/assets/js/126.90a937ca.js"><link rel="prefetch" href="/blog/assets/js/127.541a2bd8.js"><link rel="prefetch" href="/blog/assets/js/128.d197e7a9.js"><link rel="prefetch" href="/blog/assets/js/129.bd2b74bf.js"><link rel="prefetch" href="/blog/assets/js/13.a3d3aa42.js"><link rel="prefetch" href="/blog/assets/js/130.4555d2a9.js"><link rel="prefetch" href="/blog/assets/js/131.af4d4381.js"><link rel="prefetch" href="/blog/assets/js/132.15b408e6.js"><link rel="prefetch" href="/blog/assets/js/133.c6819d56.js"><link rel="prefetch" href="/blog/assets/js/134.2b49eb48.js"><link rel="prefetch" href="/blog/assets/js/135.7b5224d1.js"><link rel="prefetch" href="/blog/assets/js/136.e966c07b.js"><link rel="prefetch" href="/blog/assets/js/138.e4446fa5.js"><link rel="prefetch" href="/blog/assets/js/139.d0a5415a.js"><link rel="prefetch" href="/blog/assets/js/14.d68bef9a.js"><link rel="prefetch" href="/blog/assets/js/140.23d79a44.js"><link rel="prefetch" href="/blog/assets/js/141.e09939d0.js"><link rel="prefetch" href="/blog/assets/js/142.266a27e9.js"><link rel="prefetch" href="/blog/assets/js/143.ed3c54b1.js"><link rel="prefetch" href="/blog/assets/js/144.98c6792d.js"><link rel="prefetch" href="/blog/assets/js/145.a18f3f3f.js"><link rel="prefetch" href="/blog/assets/js/146.106bb541.js"><link rel="prefetch" href="/blog/assets/js/147.4b313651.js"><link rel="prefetch" href="/blog/assets/js/148.4a6ec42d.js"><link rel="prefetch" href="/blog/assets/js/149.9ec297ab.js"><link rel="prefetch" href="/blog/assets/js/15.81a99c55.js"><link rel="prefetch" href="/blog/assets/js/150.823ccad7.js"><link rel="prefetch" href="/blog/assets/js/151.1eee0fd4.js"><link rel="prefetch" href="/blog/assets/js/152.71ae0047.js"><link rel="prefetch" href="/blog/assets/js/153.63d5a471.js"><link rel="prefetch" href="/blog/assets/js/154.77169175.js"><link rel="prefetch" href="/blog/assets/js/155.c460c129.js"><link rel="prefetch" href="/blog/assets/js/156.793e4b57.js"><link rel="prefetch" href="/blog/assets/js/157.c9261336.js"><link rel="prefetch" href="/blog/assets/js/158.f2160023.js"><link rel="prefetch" href="/blog/assets/js/159.33ddd8b3.js"><link rel="prefetch" href="/blog/assets/js/16.6a1f4400.js"><link rel="prefetch" href="/blog/assets/js/160.cd0b03b9.js"><link rel="prefetch" href="/blog/assets/js/161.d4b3bb73.js"><link rel="prefetch" href="/blog/assets/js/162.c69e83b1.js"><link rel="prefetch" href="/blog/assets/js/163.9c1b18fa.js"><link rel="prefetch" href="/blog/assets/js/164.854148c8.js"><link rel="prefetch" href="/blog/assets/js/165.aa0c4f4d.js"><link rel="prefetch" href="/blog/assets/js/166.54fc4b36.js"><link rel="prefetch" href="/blog/assets/js/167.ca2d6801.js"><link rel="prefetch" href="/blog/assets/js/168.cf378109.js"><link rel="prefetch" href="/blog/assets/js/169.a298949f.js"><link rel="prefetch" href="/blog/assets/js/17.ad83a175.js"><link rel="prefetch" href="/blog/assets/js/170.1f5f6b47.js"><link rel="prefetch" href="/blog/assets/js/171.aec76c3b.js"><link rel="prefetch" href="/blog/assets/js/172.be4a4852.js"><link rel="prefetch" href="/blog/assets/js/173.80a0f3b5.js"><link rel="prefetch" href="/blog/assets/js/174.e3a39617.js"><link rel="prefetch" href="/blog/assets/js/175.597dc79e.js"><link rel="prefetch" href="/blog/assets/js/176.29eb04a2.js"><link rel="prefetch" href="/blog/assets/js/177.e91f6f26.js"><link rel="prefetch" href="/blog/assets/js/178.34ce2871.js"><link rel="prefetch" href="/blog/assets/js/179.f2cef142.js"><link rel="prefetch" href="/blog/assets/js/18.11cfb1b5.js"><link rel="prefetch" href="/blog/assets/js/180.327428c1.js"><link rel="prefetch" href="/blog/assets/js/181.d6f70081.js"><link rel="prefetch" href="/blog/assets/js/182.e5313823.js"><link rel="prefetch" href="/blog/assets/js/183.d08dbc32.js"><link rel="prefetch" href="/blog/assets/js/184.ccfa8d5d.js"><link rel="prefetch" href="/blog/assets/js/185.9695e392.js"><link rel="prefetch" href="/blog/assets/js/186.3a1b272d.js"><link rel="prefetch" href="/blog/assets/js/187.e11331a6.js"><link rel="prefetch" href="/blog/assets/js/188.2a3eab47.js"><link rel="prefetch" href="/blog/assets/js/189.71a6890e.js"><link rel="prefetch" href="/blog/assets/js/19.1cca0d39.js"><link rel="prefetch" href="/blog/assets/js/190.41f05291.js"><link rel="prefetch" href="/blog/assets/js/191.6db1a29f.js"><link rel="prefetch" href="/blog/assets/js/192.6d6a9425.js"><link rel="prefetch" href="/blog/assets/js/193.1ac4e1e9.js"><link rel="prefetch" href="/blog/assets/js/194.e3056d02.js"><link rel="prefetch" href="/blog/assets/js/195.937d6e29.js"><link rel="prefetch" href="/blog/assets/js/196.775b3da3.js"><link rel="prefetch" href="/blog/assets/js/197.437fe16f.js"><link rel="prefetch" href="/blog/assets/js/198.e02c3fd3.js"><link rel="prefetch" href="/blog/assets/js/199.da036572.js"><link rel="prefetch" href="/blog/assets/js/20.f58b2515.js"><link rel="prefetch" href="/blog/assets/js/200.d70ebfc1.js"><link rel="prefetch" href="/blog/assets/js/201.5a0cc6a8.js"><link rel="prefetch" href="/blog/assets/js/202.b6f4dfe9.js"><link rel="prefetch" href="/blog/assets/js/203.ac5f2eea.js"><link rel="prefetch" href="/blog/assets/js/204.e4197e35.js"><link rel="prefetch" href="/blog/assets/js/205.e988b5e5.js"><link rel="prefetch" href="/blog/assets/js/206.7d6d7ee2.js"><link rel="prefetch" href="/blog/assets/js/207.e9476276.js"><link rel="prefetch" href="/blog/assets/js/208.90d387ec.js"><link rel="prefetch" href="/blog/assets/js/209.01278130.js"><link rel="prefetch" href="/blog/assets/js/21.f2eb7cbe.js"><link rel="prefetch" href="/blog/assets/js/210.08914606.js"><link rel="prefetch" href="/blog/assets/js/211.b5ae3862.js"><link rel="prefetch" href="/blog/assets/js/212.03a9909c.js"><link rel="prefetch" href="/blog/assets/js/213.88999a25.js"><link rel="prefetch" href="/blog/assets/js/214.5e6517ae.js"><link rel="prefetch" href="/blog/assets/js/215.7c05faa3.js"><link rel="prefetch" href="/blog/assets/js/216.0c0d0250.js"><link rel="prefetch" href="/blog/assets/js/217.3e6a1882.js"><link rel="prefetch" href="/blog/assets/js/218.7bdaa47b.js"><link rel="prefetch" href="/blog/assets/js/219.4a9b382a.js"><link rel="prefetch" href="/blog/assets/js/22.0225f4f3.js"><link rel="prefetch" href="/blog/assets/js/220.da13afe0.js"><link rel="prefetch" href="/blog/assets/js/221.b93baddd.js"><link rel="prefetch" href="/blog/assets/js/222.6f88fa87.js"><link rel="prefetch" href="/blog/assets/js/223.23532ff7.js"><link rel="prefetch" href="/blog/assets/js/224.bba40504.js"><link rel="prefetch" href="/blog/assets/js/225.e87911f0.js"><link rel="prefetch" href="/blog/assets/js/226.27fcd8f6.js"><link rel="prefetch" href="/blog/assets/js/227.7075a8c3.js"><link rel="prefetch" href="/blog/assets/js/228.d5363587.js"><link rel="prefetch" href="/blog/assets/js/229.95d21664.js"><link rel="prefetch" href="/blog/assets/js/23.203b3a9e.js"><link rel="prefetch" href="/blog/assets/js/230.eee47d34.js"><link rel="prefetch" href="/blog/assets/js/231.686012e1.js"><link rel="prefetch" href="/blog/assets/js/232.d780f01b.js"><link rel="prefetch" href="/blog/assets/js/233.fba323db.js"><link rel="prefetch" href="/blog/assets/js/234.7ac11688.js"><link rel="prefetch" href="/blog/assets/js/235.61ba2d32.js"><link rel="prefetch" href="/blog/assets/js/24.26ad942d.js"><link rel="prefetch" href="/blog/assets/js/25.e9864d4c.js"><link rel="prefetch" href="/blog/assets/js/26.1a4e2ed9.js"><link rel="prefetch" href="/blog/assets/js/27.f56ff53e.js"><link rel="prefetch" href="/blog/assets/js/28.3c5bd15e.js"><link rel="prefetch" href="/blog/assets/js/29.0104f169.js"><link rel="prefetch" href="/blog/assets/js/3.3ec6f00b.js"><link rel="prefetch" href="/blog/assets/js/30.9aaf650a.js"><link rel="prefetch" href="/blog/assets/js/31.50bfe700.js"><link rel="prefetch" href="/blog/assets/js/32.33630021.js"><link rel="prefetch" href="/blog/assets/js/33.703693c2.js"><link rel="prefetch" href="/blog/assets/js/34.51cfd584.js"><link rel="prefetch" href="/blog/assets/js/35.5614a593.js"><link rel="prefetch" href="/blog/assets/js/36.3f9fb418.js"><link rel="prefetch" href="/blog/assets/js/37.d3471a6e.js"><link rel="prefetch" href="/blog/assets/js/38.303beb9a.js"><link rel="prefetch" href="/blog/assets/js/39.528e5c8c.js"><link rel="prefetch" href="/blog/assets/js/4.f7a68e82.js"><link rel="prefetch" href="/blog/assets/js/40.5d37d2ac.js"><link rel="prefetch" href="/blog/assets/js/41.5e434fb6.js"><link rel="prefetch" href="/blog/assets/js/42.58ebb1e1.js"><link rel="prefetch" href="/blog/assets/js/43.f7344b04.js"><link rel="prefetch" href="/blog/assets/js/44.ba8e2c32.js"><link rel="prefetch" href="/blog/assets/js/45.b59d07a4.js"><link rel="prefetch" href="/blog/assets/js/46.cf56a467.js"><link rel="prefetch" href="/blog/assets/js/47.2307b39c.js"><link rel="prefetch" href="/blog/assets/js/48.0f967628.js"><link rel="prefetch" href="/blog/assets/js/49.e9c76177.js"><link rel="prefetch" href="/blog/assets/js/5.43eb1773.js"><link rel="prefetch" href="/blog/assets/js/50.ef1c92fd.js"><link rel="prefetch" href="/blog/assets/js/51.472db098.js"><link rel="prefetch" href="/blog/assets/js/52.b151aea0.js"><link rel="prefetch" href="/blog/assets/js/53.0df4c526.js"><link rel="prefetch" href="/blog/assets/js/54.352990e8.js"><link rel="prefetch" href="/blog/assets/js/55.27accd61.js"><link rel="prefetch" href="/blog/assets/js/56.91d392d0.js"><link rel="prefetch" href="/blog/assets/js/57.4f8d55c3.js"><link rel="prefetch" href="/blog/assets/js/58.aba5c165.js"><link rel="prefetch" href="/blog/assets/js/59.1f31aefa.js"><link rel="prefetch" href="/blog/assets/js/6.709e31d8.js"><link rel="prefetch" href="/blog/assets/js/60.c4c2ad7c.js"><link rel="prefetch" href="/blog/assets/js/61.84c44795.js"><link rel="prefetch" href="/blog/assets/js/62.847d5a79.js"><link rel="prefetch" href="/blog/assets/js/63.4526d774.js"><link rel="prefetch" href="/blog/assets/js/64.149c457f.js"><link rel="prefetch" href="/blog/assets/js/65.ffb7241e.js"><link rel="prefetch" href="/blog/assets/js/66.ab3a1fd7.js"><link rel="prefetch" href="/blog/assets/js/67.960d17a4.js"><link rel="prefetch" href="/blog/assets/js/68.1ecea3e5.js"><link rel="prefetch" href="/blog/assets/js/69.24a059f9.js"><link rel="prefetch" href="/blog/assets/js/7.3123b0d0.js"><link rel="prefetch" href="/blog/assets/js/70.087b119f.js"><link rel="prefetch" href="/blog/assets/js/71.36ec64ad.js"><link rel="prefetch" href="/blog/assets/js/72.72180002.js"><link rel="prefetch" href="/blog/assets/js/73.76a3edbc.js"><link rel="prefetch" href="/blog/assets/js/74.fb379a54.js"><link rel="prefetch" href="/blog/assets/js/75.eaa559bd.js"><link rel="prefetch" href="/blog/assets/js/76.156bd9c3.js"><link rel="prefetch" href="/blog/assets/js/77.123a161c.js"><link rel="prefetch" href="/blog/assets/js/78.19a324be.js"><link rel="prefetch" href="/blog/assets/js/79.e24877d1.js"><link rel="prefetch" href="/blog/assets/js/8.5c81f7fc.js"><link rel="prefetch" href="/blog/assets/js/80.22910223.js"><link rel="prefetch" href="/blog/assets/js/81.169a78ab.js"><link rel="prefetch" href="/blog/assets/js/82.c300aae5.js"><link rel="prefetch" href="/blog/assets/js/83.fc555e72.js"><link rel="prefetch" href="/blog/assets/js/84.8e8a9c99.js"><link rel="prefetch" href="/blog/assets/js/85.7c060e20.js"><link rel="prefetch" href="/blog/assets/js/86.946a80b1.js"><link rel="prefetch" href="/blog/assets/js/87.8e5e2c47.js"><link rel="prefetch" href="/blog/assets/js/88.d2f97880.js"><link rel="prefetch" href="/blog/assets/js/89.a7a762a6.js"><link rel="prefetch" href="/blog/assets/js/9.dde6002e.js"><link rel="prefetch" href="/blog/assets/js/90.c6447971.js"><link rel="prefetch" href="/blog/assets/js/91.403877ec.js"><link rel="prefetch" href="/blog/assets/js/92.44bb8649.js"><link rel="prefetch" href="/blog/assets/js/93.b9f553db.js"><link rel="prefetch" href="/blog/assets/js/94.27628f49.js"><link rel="prefetch" href="/blog/assets/js/95.7ad3dc73.js"><link rel="prefetch" href="/blog/assets/js/96.adc8f3f6.js"><link rel="prefetch" href="/blog/assets/js/97.f5b76103.js"><link rel="prefetch" href="/blog/assets/js/98.e8878d44.js"><link rel="prefetch" href="/blog/assets/js/99.037be397.js">
    <link rel="stylesheet" href="/blog/assets/css/0.styles.5cae76fb.css">
  </head>
  <body class="theme-mode-light">
    <div id="app" data-server-rendered="true"><div class="theme-container sidebar-open have-rightmenu"><header class="navbar blur"><div title="目录" class="sidebar-button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512" class="icon"><path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div> <a href="/blog/" class="home-link router-link-active"><img src="/blog/img/logo.png" alt="Evan's blog" class="logo"> <span class="site-name can-hide">Evan's blog</span></a> <div class="links"><div class="search-box"><input aria-label="Search" autocomplete="off" spellcheck="false" value=""> <!----></div> <nav class="nav-links can-hide"><div class="nav-item"><a href="/blog/" class="nav-link">首页</a></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="前端" class="dropdown-title"><a href="/blog/web/" class="link-title">前端</a> <span class="title" style="display:none;">前端</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><h4>前端文章</h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/blog/pages/8143cc480faf9a11/" class="nav-link">JavaScript</a></li></ul></li><li class="dropdown-item"><h4>学习笔记</h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/blog/note/javascript/" class="nav-link">《JavaScript教程》</a></li><li class="dropdown-subitem"><a href="/blog/note/js/" class="nav-link">《JavaScript高级程序设计》</a></li><li class="dropdown-subitem"><a href="/blog/note/es6/" class="nav-link">《ES6 教程》</a></li><li class="dropdown-subitem"><a href="/blog/note/vue/" class="nav-link">《Vue》</a></li><li class="dropdown-subitem"><a href="/blog/note/react/" class="nav-link">《React》</a></li><li class="dropdown-subitem"><a href="/blog/note/typescript-axios/" class="nav-link">《TypeScript 从零实现 axios》</a></li><li class="dropdown-subitem"><a href="/blog/note/git/" class="nav-link">《Git》</a></li><li class="dropdown-subitem"><a href="/blog/pages/51afd6/" class="nav-link">TypeScript</a></li><li class="dropdown-subitem"><a href="/blog/pages/4643cd/" class="nav-link">JS设计模式总结</a></li></ul></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="页面" class="dropdown-title"><a href="/blog/ui/" class="link-title">页面</a> <span class="title" style="display:none;">页面</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/blog/pages/8309a5b876fc95e3/" class="nav-link">HTML</a></li><li class="dropdown-item"><!----> <a href="/blog/pages/0a83b083bdf257cb/" class="nav-link">CSS</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="技术" class="dropdown-title"><a href="/blog/technology/" class="link-title">技术</a> <span class="title" style="display:none;">技术</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/blog/pages/9a7ee40fc232253e/" class="nav-link">技术文档</a></li><li class="dropdown-item"><!----> <a href="/blog/pages/4c778760be26d8b3/" class="nav-link">GitHub技巧</a></li><li class="dropdown-item"><!----> <a href="/blog/pages/117708e0af7f0bd9/" class="nav-link">Nodejs</a></li><li class="dropdown-item"><!----> <a href="/blog/pages/41f87d890d0a02af/" class="nav-link">博客搭建</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="更多" class="dropdown-title"><a href="/blog/more/" class="link-title">更多</a> <span class="title" style="display:none;">更多</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/blog/pages/f2a556/" class="nav-link">学习</a></li><li class="dropdown-item"><!----> <a href="/blog/pages/aea6571b7a8bae86/" class="nav-link">面试</a></li><li class="dropdown-item"><!----> <a href="/blog/pages/2d615df9a36a98ed/" class="nav-link">心情杂货</a></li><li class="dropdown-item"><!----> <a href="/blog/pages/baaa02/" class="nav-link">实用技巧</a></li><li class="dropdown-item"><!----> <a href="/blog/friends/" class="nav-link">友情链接</a></li></ul></div></div><div class="nav-item"><a href="/blog/about/" class="nav-link">关于</a></div><div class="nav-item"><a href="/blog/pages/beb6c0bd8a66cea6/" class="nav-link">收藏</a></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="索引" class="dropdown-title"><a href="/blog/archives/" class="link-title">索引</a> <span class="title" style="display:none;">索引</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/blog/categories/" class="nav-link">分类</a></li><li class="dropdown-item"><!----> <a href="/blog/tags/" class="nav-link">标签</a></li><li class="dropdown-item"><!----> <a href="/blog/archives/" class="nav-link">归档</a></li></ul></div></div> <a href="https://github.com/xugaoyi/vuepress-theme-vdoing" target="_blank" rel="noopener noreferrer" class="repo-link">
    GitHub
    <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></nav></div></header> <div class="sidebar-mask"></div> <div class="sidebar-hover-trigger"></div> <aside class="sidebar" style="display:none;"><div class="blogger"><img src="https://cdn.jsdelivr.net/gh/xugaoyi/image_store/blog/20200103123203.jpg"> <div class="blogger-info"><h3>Evan Xu</h3> <span>前端界的小学生</span></div></div> <nav class="nav-links"><div class="nav-item"><a href="/blog/" class="nav-link">首页</a></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="前端" class="dropdown-title"><a href="/blog/web/" class="link-title">前端</a> <span class="title" style="display:none;">前端</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><h4>前端文章</h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/blog/pages/8143cc480faf9a11/" class="nav-link">JavaScript</a></li></ul></li><li class="dropdown-item"><h4>学习笔记</h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/blog/note/javascript/" class="nav-link">《JavaScript教程》</a></li><li class="dropdown-subitem"><a href="/blog/note/js/" class="nav-link">《JavaScript高级程序设计》</a></li><li class="dropdown-subitem"><a href="/blog/note/es6/" class="nav-link">《ES6 教程》</a></li><li class="dropdown-subitem"><a href="/blog/note/vue/" class="nav-link">《Vue》</a></li><li class="dropdown-subitem"><a href="/blog/note/react/" class="nav-link">《React》</a></li><li class="dropdown-subitem"><a href="/blog/note/typescript-axios/" class="nav-link">《TypeScript 从零实现 axios》</a></li><li class="dropdown-subitem"><a href="/blog/note/git/" class="nav-link">《Git》</a></li><li class="dropdown-subitem"><a href="/blog/pages/51afd6/" class="nav-link">TypeScript</a></li><li class="dropdown-subitem"><a href="/blog/pages/4643cd/" class="nav-link">JS设计模式总结</a></li></ul></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="页面" class="dropdown-title"><a href="/blog/ui/" class="link-title">页面</a> <span class="title" style="display:none;">页面</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/blog/pages/8309a5b876fc95e3/" class="nav-link">HTML</a></li><li class="dropdown-item"><!----> <a href="/blog/pages/0a83b083bdf257cb/" class="nav-link">CSS</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="技术" class="dropdown-title"><a href="/blog/technology/" class="link-title">技术</a> <span class="title" style="display:none;">技术</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/blog/pages/9a7ee40fc232253e/" class="nav-link">技术文档</a></li><li class="dropdown-item"><!----> <a href="/blog/pages/4c778760be26d8b3/" class="nav-link">GitHub技巧</a></li><li class="dropdown-item"><!----> <a href="/blog/pages/117708e0af7f0bd9/" class="nav-link">Nodejs</a></li><li class="dropdown-item"><!----> <a href="/blog/pages/41f87d890d0a02af/" class="nav-link">博客搭建</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="更多" class="dropdown-title"><a href="/blog/more/" class="link-title">更多</a> <span class="title" style="display:none;">更多</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/blog/pages/f2a556/" class="nav-link">学习</a></li><li class="dropdown-item"><!----> <a href="/blog/pages/aea6571b7a8bae86/" class="nav-link">面试</a></li><li class="dropdown-item"><!----> <a href="/blog/pages/2d615df9a36a98ed/" class="nav-link">心情杂货</a></li><li class="dropdown-item"><!----> <a href="/blog/pages/baaa02/" class="nav-link">实用技巧</a></li><li class="dropdown-item"><!----> <a href="/blog/friends/" class="nav-link">友情链接</a></li></ul></div></div><div class="nav-item"><a href="/blog/about/" class="nav-link">关于</a></div><div class="nav-item"><a href="/blog/pages/beb6c0bd8a66cea6/" class="nav-link">收藏</a></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="索引" class="dropdown-title"><a href="/blog/archives/" class="link-title">索引</a> <span class="title" style="display:none;">索引</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/blog/categories/" class="nav-link">分类</a></li><li class="dropdown-item"><!----> <a href="/blog/tags/" class="nav-link">标签</a></li><li class="dropdown-item"><!----> <a href="/blog/archives/" class="nav-link">归档</a></li></ul></div></div> <a href="https://github.com/xugaoyi/vuepress-theme-vdoing" target="_blank" rel="noopener noreferrer" class="repo-link">
    GitHub
    <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></nav>  <ul class="sidebar-links"><li><a href="/blog/pages/0796ba76b4b55368/" class="sidebar-link">基础</a></li><li><a href="/blog/pages/74d2ab3fbfeaaa68/" class="sidebar-link">内置对象</a></li><li><a href="/blog/pages/659b5af5e2e704e0/" class="sidebar-link">面向对象</a></li><li><a href="/blog/pages/d61b1cb4cdac1f63/" class="sidebar-link">异步操作</a></li><li><a href="/blog/pages/7d961b8030c6099e/" class="sidebar-link">DOM</a></li><li><a href="/blog/pages/10b2761db5a8e089/" aria-current="page" class="active sidebar-link">事件</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/blog/pages/10b2761db5a8e089/#一、eventtarget-接口" class="sidebar-link">一、EventTarget 接口</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/blog/pages/10b2761db5a8e089/#_1、概述" class="sidebar-link">1、概述</a></li><li class="sidebar-sub-header"><a href="/blog/pages/10b2761db5a8e089/#_2、eventtarget-addeventlistener" class="sidebar-link">2、EventTarget.addEventListener()</a></li><li class="sidebar-sub-header"><a href="/blog/pages/10b2761db5a8e089/#_3、eventtarget-removeeventlistener" class="sidebar-link">3、EventTarget.removeEventListener()</a></li><li class="sidebar-sub-header"><a href="/blog/pages/10b2761db5a8e089/#_4、eventtarget-dispatchevent" class="sidebar-link">4、EventTarget.dispatchEvent()</a></li></ul></li><li class="sidebar-sub-header"><a href="/blog/pages/10b2761db5a8e089/#二、事件模型" class="sidebar-link">二、事件模型</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/blog/pages/10b2761db5a8e089/#_1、监听函数" class="sidebar-link">1、监听函数</a></li><li class="sidebar-sub-header"><a href="/blog/pages/10b2761db5a8e089/#_2、this-的指向-指向元素节点" class="sidebar-link">2、this 的指向 （指向元素节点）</a></li><li class="sidebar-sub-header"><a href="/blog/pages/10b2761db5a8e089/#_3、事件的传播-捕获、目标、冒泡" class="sidebar-link">3、事件的传播（捕获、目标、冒泡）</a></li><li class="sidebar-sub-header"><a href="/blog/pages/10b2761db5a8e089/#_4、事件的代理" class="sidebar-link">4、事件的代理</a></li></ul></li><li class="sidebar-sub-header"><a href="/blog/pages/10b2761db5a8e089/#三、event-对象" class="sidebar-link">三、Event 对象</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/blog/pages/10b2761db5a8e089/#_1-概述" class="sidebar-link">1. 概述</a></li><li class="sidebar-sub-header"><a href="/blog/pages/10b2761db5a8e089/#_2-实例属性" class="sidebar-link">2. 实例属性</a></li><li class="sidebar-sub-header"><a href="/blog/pages/10b2761db5a8e089/#_3、实例方法" class="sidebar-link">3、实例方法</a></li></ul></li><li class="sidebar-sub-header"><a href="/blog/pages/10b2761db5a8e089/#四、鼠标事件" class="sidebar-link">四、鼠标事件</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/blog/pages/10b2761db5a8e089/#_1、鼠标事件的种类" class="sidebar-link">1、鼠标事件的种类</a></li><li class="sidebar-sub-header"><a href="/blog/pages/10b2761db5a8e089/#_2、mouseevent-接口概述" class="sidebar-link">2、MouseEvent 接口概述</a></li><li class="sidebar-sub-header"><a href="/blog/pages/10b2761db5a8e089/#_3、mouseevent-接口的实例属性" class="sidebar-link">3、MouseEvent 接口的实例属性</a></li><li class="sidebar-sub-header"><a href="/blog/pages/10b2761db5a8e089/#_4、mouseevent-接口的实例方法" class="sidebar-link">4、MouseEvent 接口的实例方法</a></li><li class="sidebar-sub-header"><a href="/blog/pages/10b2761db5a8e089/#_5、wheelevent-接口-滚轮" class="sidebar-link">5、WheelEvent 接口 （滚轮）</a></li></ul></li><li class="sidebar-sub-header"><a href="/blog/pages/10b2761db5a8e089/#五、键盘事件" class="sidebar-link">五、键盘事件</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/blog/pages/10b2761db5a8e089/#_1、键盘事件的种类" class="sidebar-link">1、键盘事件的种类</a></li><li class="sidebar-sub-header"><a href="/blog/pages/10b2761db5a8e089/#_2、keyboardevent-接口概述" class="sidebar-link">2、KeyboardEvent 接口概述</a></li><li class="sidebar-sub-header"><a href="/blog/pages/10b2761db5a8e089/#_3、keyboardevent-的实例属性" class="sidebar-link">3、KeyboardEvent 的实例属性</a></li><li class="sidebar-sub-header"><a href="/blog/pages/10b2761db5a8e089/#_4、keyboardevent-的实例方法" class="sidebar-link">4、KeyboardEvent 的实例方法</a></li></ul></li><li class="sidebar-sub-header"><a href="/blog/pages/10b2761db5a8e089/#六、进度事件" class="sidebar-link">六、进度事件</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/blog/pages/10b2761db5a8e089/#_1、进度事件的种类" class="sidebar-link">1、进度事件的种类</a></li><li class="sidebar-sub-header"><a href="/blog/pages/10b2761db5a8e089/#_2、progressevent-接口" class="sidebar-link">2、ProgressEvent 接口</a></li></ul></li><li class="sidebar-sub-header"><a href="/blog/pages/10b2761db5a8e089/#七、表单事件" class="sidebar-link">七、表单事件</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/blog/pages/10b2761db5a8e089/#_1、表单事件的种类" class="sidebar-link">1、表单事件的种类</a></li><li class="sidebar-sub-header"><a href="/blog/pages/10b2761db5a8e089/#_2、inputevent-接口-input事件的实例" class="sidebar-link">2、InputEvent 接口（input事件的实例）</a></li></ul></li><li class="sidebar-sub-header"><a href="/blog/pages/10b2761db5a8e089/#八、触摸事件" class="sidebar-link">八、触摸事件</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/blog/pages/10b2761db5a8e089/#_1、触摸操作概述" class="sidebar-link">1、触摸操作概述</a></li><li class="sidebar-sub-header"><a href="/blog/pages/10b2761db5a8e089/#_2、touch-接口" class="sidebar-link">2、Touch 接口</a></li><li class="sidebar-sub-header"><a href="/blog/pages/10b2761db5a8e089/#_3、touchlist-接口" class="sidebar-link">3、TouchList 接口</a></li><li class="sidebar-sub-header"><a href="/blog/pages/10b2761db5a8e089/#_4、touchevent-接口" class="sidebar-link">4、TouchEvent 接口</a></li><li class="sidebar-sub-header"><a href="/blog/pages/10b2761db5a8e089/#_5、触摸事件的种类" class="sidebar-link">5、触摸事件的种类</a></li></ul></li><li class="sidebar-sub-header"><a href="/blog/pages/10b2761db5a8e089/#九、拖拉事件" class="sidebar-link">九、拖拉事件</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/blog/pages/10b2761db5a8e089/#_1、拖拉事件的种类" class="sidebar-link">1、拖拉事件的种类</a></li><li class="sidebar-sub-header"><a href="/blog/pages/10b2761db5a8e089/#_2、dragevent-接口" class="sidebar-link">2、DragEvent 接口</a></li><li class="sidebar-sub-header"><a href="/blog/pages/10b2761db5a8e089/#_3、datatransfer-接口概述" class="sidebar-link">3、DataTransfer 接口概述</a></li><li class="sidebar-sub-header"><a href="/blog/pages/10b2761db5a8e089/#_4、datatransfer-的实例属性" class="sidebar-link">4、DataTransfer 的实例属性</a></li><li class="sidebar-sub-header"><a href="/blog/pages/10b2761db5a8e089/#_5、datatransfer-的实例方法" class="sidebar-link">5、DataTransfer 的实例方法</a></li></ul></li><li class="sidebar-sub-header"><a href="/blog/pages/10b2761db5a8e089/#十、其他常见事件" class="sidebar-link">十、其他常见事件</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/blog/pages/10b2761db5a8e089/#_1、资源事件" class="sidebar-link">1、资源事件</a></li><li class="sidebar-sub-header"><a href="/blog/pages/10b2761db5a8e089/#_2、session-历史事件" class="sidebar-link">2、session 历史事件</a></li><li class="sidebar-sub-header"><a href="/blog/pages/10b2761db5a8e089/#_3、网页状态事件" class="sidebar-link">3、网页状态事件</a></li><li class="sidebar-sub-header"><a href="/blog/pages/10b2761db5a8e089/#_4、窗口事件" class="sidebar-link">4、窗口事件</a></li><li class="sidebar-sub-header"><a href="/blog/pages/10b2761db5a8e089/#_5、剪贴板事件" class="sidebar-link">5、剪贴板事件</a></li><li class="sidebar-sub-header"><a href="/blog/pages/10b2761db5a8e089/#_6、焦点事件" class="sidebar-link">6、焦点事件</a></li><li class="sidebar-sub-header"><a href="/blog/pages/10b2761db5a8e089/#_7、customevent-接口-自定义事件" class="sidebar-link">7、CustomEvent 接口（自定义事件）</a></li></ul></li><li class="sidebar-sub-header"><a href="/blog/pages/10b2761db5a8e089/#十一、globaleventhandlers-接口-全局事件处理接口" class="sidebar-link">十一、GlobalEventHandlers 接口 （全局事件处理接口）</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/blog/pages/10b2761db5a8e089/#_1、globaleventhandlers-onabort-中断事件" class="sidebar-link">1、GlobalEventHandlers.onabort （中断事件）</a></li><li class="sidebar-sub-header"><a href="/blog/pages/10b2761db5a8e089/#_2、globaleventhandlers-onerror-错误事件" class="sidebar-link">2、GlobalEventHandlers.onerror （错误事件）</a></li><li class="sidebar-sub-header"><a href="/blog/pages/10b2761db5a8e089/#_3、globaleventhandlers-onload-加载完成事件-、globaleventhandlers-onloadstart-开始加载事件" class="sidebar-link">3、GlobalEventHandlers.onload（加载完成事件）、GlobalEventHandlers.onloadstart（开始加载事件）</a></li><li class="sidebar-sub-header"><a href="/blog/pages/10b2761db5a8e089/#_4、globaleventhandlers-onfocus-获取焦点事件-globaleventhandlers-onblur-失去焦点事件" class="sidebar-link">4、GlobalEventHandlers.onfocus（获取焦点事件），GlobalEventHandlers.onblur（失去焦点事件）</a></li><li class="sidebar-sub-header"><a href="/blog/pages/10b2761db5a8e089/#_5、globaleventhandlers-onscroll-滚动事件" class="sidebar-link">5、GlobalEventHandlers.onscroll（滚动事件）</a></li><li class="sidebar-sub-header"><a href="/blog/pages/10b2761db5a8e089/#_6、globaleventhandlers-oncontextmenu-右键菜单事件-globaleventhandlers-onshow-显示右键菜单时触发" class="sidebar-link">6、GlobalEventHandlers.oncontextmenu（右键菜单事件），GlobalEventHandlers.onshow（显示右键菜单时触发）</a></li><li class="sidebar-sub-header"><a href="/blog/pages/10b2761db5a8e089/#_7、其他的事件属性" class="sidebar-link">7、其他的事件属性</a></li></ul></li><li class="sidebar-sub-header"><a href="/blog/pages/10b2761db5a8e089/#文档" class="sidebar-link">文档</a></li></ul></li><li><a href="/blog/pages/bab4930124ad2c10/" class="sidebar-link">浏览器模型</a></li></ul> </aside> <div><main class="page"><div class="theme-vdoing-wrapper "><div class="articleInfo-wrap" data-v-0c557b5e><div class="articleInfo" data-v-0c557b5e><ul class="breadcrumbs" data-v-0c557b5e><li data-v-0c557b5e><a href="/blog/" title="首页" class="iconfont icon-home router-link-active" data-v-0c557b5e></a></li> <li data-v-0c557b5e><a href="/blog/note/javascript/#《JavaScript教程》笔记" data-v-0c557b5e>《JavaScript教程》笔记</a></li></ul> <div class="info" data-v-0c557b5e><div title="作者" class="author iconfont icon-touxiang" data-v-0c557b5e><a href="https://github.com/xugaoyi" target="_blank" title="作者" class="beLink" data-v-0c557b5e>xugaoyi</a></div> <div title="创建时间" class="date iconfont icon-riqi" data-v-0c557b5e><a href="javascript:;" data-v-0c557b5e>2020-01-12</a></div> <!----></div></div></div> <!----> <div class="content-wrapper"><div class="right-menu-wrapper"><div class="right-menu-margin"><div class="right-menu-content"></div></div></div> <h1><img src="">事件<!----></h1>  <div class="theme-vdoing-content content__default"><h1 id="事件"><a href="#事件" class="header-anchor">#</a> 事件</h1> <h2 id="一、eventtarget-接口"><a href="#一、eventtarget-接口" class="header-anchor">#</a> 一、EventTarget 接口</h2> <p>事件的本质是程序各个组成部分之间的一种通信方式，也是异步编程的一种实现。DOM 支持大量的事件，本章开始介绍 <strong>DOM 的事件编程</strong>。</p> <h3 id="_1、概述"><a href="#_1、概述" class="header-anchor">#</a> 1、概述</h3> <p><strong>DOM 的事件操作（监听和触发），都定义在<code>EventTarget</code>接口</strong>。所有节点对象都部署了这个接口，其他一些需要事件通信的浏览器内置对象（比如，<code>XMLHttpRequest</code>、<code>AudioNode</code>、<code>AudioContext</code>）也部署了这个接口。</p> <p>该接口主要提供三个实例方法。</p> <ul><li><code>addEventListener</code>：绑定事件的监听函数</li> <li><code>removeEventListener</code>：移除事件的监听函数</li> <li><code>dispatchEvent</code>：触发事件</li></ul> <h3 id="_2、eventtarget-addeventlistener"><a href="#_2、eventtarget-addeventlistener" class="header-anchor">#</a> 2、EventTarget.addEventListener()</h3> <p><code>EventTarget.addEventListener()</code>用于<strong>在当前节点或对象上，定义一个特定事件的监听函数</strong>。<strong>一旦这个事件发生，就会执行监听函数</strong>。该方法没有返回值。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code>target<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span>type<span class="token punctuation">,</span> listener<span class="token punctuation">[</span><span class="token punctuation">,</span> useCapture<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 事件名称，监听函数 [，是否在捕获阶段触发]</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br></div></div><p>该方法接受三个参数。</p> <ul><li><code>type</code>：事件名称，大小写敏感。</li> <li><code>listener</code>：监听函数。事件发生时，会调用该监听函数。</li> <li><code>useCapture</code>：布尔值，表示监听函数是否在捕获阶段（capture）触发（参见后文《事件的传播》部分），默认为<code>false</code>（监听函数只在冒泡阶段被触发）。该参数可选。</li></ul> <p>下面是一个例子。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token keyword">function</span> <span class="token function">hello</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Hello world'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">var</span> button <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'btn'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
button<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'click'</span><span class="token punctuation">,</span> hello<span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br></div></div><p>上面代码中，<code>button</code>节点的<code>addEventListener</code>方法绑定<code>click</code>事件的监听函数<code>hello</code>，该函数只在冒泡阶段触发。</p> <p>关于参数，有两个地方需要注意。</p> <p>首先，第二个参数除了监听函数，还可以是一个具有<code>handleEvent</code>方法的对象。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code>buttonElement<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'click'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
  <span class="token function-variable function">handleEvent</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'click'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br></div></div><p>上面代码中，<code>addEventListener</code>方法的第二个参数，就是一个具有<code>handleEvent</code>方法的对象。</p> <p>其次，<strong>第三个参数除了布尔值<code>useCapture</code>，还可以是一个属性配置对象</strong>。该对象有以下属性。</p> <blockquote><ul><li><code>capture</code>：布尔值，表示该事件是否在<code>捕获阶段</code>触发监听函数。</li> <li><code>once</code>：布尔值，表示监听函数是否只触发一次，然后就自动移除。</li> <li><code>passive</code>：布尔值，表示监听函数不会调用事件的<code>preventDefault</code>方法。如果监听函数调用了，浏览器将忽略这个要求，并在监控台输出一行警告。</li></ul></blockquote> <p>如果希望事件监听函数<strong>只执行一次</strong>，可以打开属性配置对象的<code>once</code>属性。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code>element<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'click'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment">// 只执行一次的代码</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><span class="token literal-property property">once</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br></div></div><p><code>addEventListener</code>方法可以为针对当前对象的同一个事件，添加多个不同的监听函数。这些函数按照添加顺序触发，即先添加先触发。如果为同一个事件多次添加同一个监听函数，该函数只会执行一次，多余的添加将自动被去除（不必使用<code>removeEventListener</code>方法手动去除）。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token keyword">function</span> <span class="token function">hello</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Hello world'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

document<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'click'</span><span class="token punctuation">,</span> hello<span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
document<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'click'</span><span class="token punctuation">,</span> hello<span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br></div></div><p>执行上面代码，点击文档只会输出一行<code>Hello world</code>。</p> <p>如果<strong>希望向监听函数传递参数，可以用匿名函数包装一下监听函数。</strong></p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token keyword">function</span> <span class="token function">print</span><span class="token punctuation">(</span><span class="token parameter">x</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>x<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">var</span> el <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'div1'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
el<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'click'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">print</span><span class="token punctuation">(</span><span class="token string">'Hello'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br></div></div><p>上面代码通过匿名函数，向监听函数<code>print</code>传递了一个参数。</p> <p>监听函数<strong>内部的<code>this</code>，指向当前事件所在的那个对象。</strong></p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token comment">// HTML 代码如下</span>
<span class="token comment">// &lt;p id=&quot;para&quot;&gt;Hello&lt;/p&gt;</span>
<span class="token keyword">var</span> para <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'para'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
para<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'click'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>nodeName<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// &quot;P&quot;</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br></div></div><p>上面代码中，监听函数内部的<code>this</code>指向事件所在的对象<code>para</code>。</p> <h3 id="_3、eventtarget-removeeventlistener"><a href="#_3、eventtarget-removeeventlistener" class="header-anchor">#</a> 3、EventTarget.removeEventListener()</h3> <p><code>EventTarget.removeEventListener</code>方法<strong>用来移除<code>addEventListener</code>方法添加的事件监听函数</strong>。该方法没有返回值。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code>div<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'click'</span><span class="token punctuation">,</span> listener<span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
div<span class="token punctuation">.</span><span class="token function">removeEventListener</span><span class="token punctuation">(</span><span class="token string">'click'</span><span class="token punctuation">,</span> listener<span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br></div></div><p><code>removeEventListener</code>方法的参数，与<code>addEventListener</code>方法完全一致。它的第一个参数“事件类型”，大小写敏感。</p> <p>注意，<code>removeEventListener</code>方法移除的监听函数，必须是<code>addEventListener</code>方法添加的那个监听函数，而且必须在同一个元素节点，否则无效。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code>div<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'click'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
div<span class="token punctuation">.</span><span class="token function">removeEventListener</span><span class="token punctuation">(</span><span class="token string">'click'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">// 移除无效，因为不是同一个监听函数</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br></div></div><p>上面代码中，<code>removeEventListener</code>方法无效，因为监听函数不是同一个匿名函数。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code>element<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'mousedown'</span><span class="token punctuation">,</span> handleMouseDown<span class="token punctuation">,</span> <span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
element<span class="token punctuation">.</span><span class="token function">removeEventListener</span><span class="token punctuation">(</span><span class="token string">&quot;mousedown&quot;</span><span class="token punctuation">,</span> handleMouseDown<span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 移除无效，第三个参数不一样</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br></div></div><p>上面代码中，<code>removeEventListener</code>方法也是无效的，因为第三个参数不一样。</p> <h3 id="_4、eventtarget-dispatchevent"><a href="#_4、eventtarget-dispatchevent" class="header-anchor">#</a> 4、EventTarget.dispatchEvent()</h3> <p><code>EventTarget.dispatchEvent</code>方法在当前节点上<strong>触发指定事件，从而触发监听函数的执行。该方法返回一个布尔值</strong>，只要有一个监听函数调用了<code>Event.preventDefault()</code>，则返回值为<code>false</code>，否则为<code>true</code>。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code>target<span class="token punctuation">.</span><span class="token function">dispatchEvent</span><span class="token punctuation">(</span>event<span class="token punctuation">)</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><p><code>dispatchEvent</code>方法的<strong>参数是一个<code>Event</code>对象的实例</strong>（详见《Event 对象》章节）。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code>para<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'click'</span><span class="token punctuation">,</span> hello<span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">var</span> event <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Event</span><span class="token punctuation">(</span><span class="token string">'click'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
para<span class="token punctuation">.</span><span class="token function">dispatchEvent</span><span class="token punctuation">(</span>event<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br></div></div><p>上面代码在当前节点触发了<code>click</code>事件。</p> <p>如果<code>dispatchEvent</code>方法的参数为空，或者不是一个有效的事件对象，将报错。</p> <p>下面代码根据<code>dispatchEvent</code>方法的返回值，<strong>判断事件是否被取消</strong>了。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token keyword">var</span> canceled <span class="token operator">=</span> <span class="token operator">!</span>cb<span class="token punctuation">.</span><span class="token function">dispatchEvent</span><span class="token punctuation">(</span>event<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>canceled<span class="token punctuation">)</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'事件取消'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'事件未取消'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br></div></div><h2 id="二、事件模型"><a href="#二、事件模型" class="header-anchor">#</a> 二、事件模型</h2> <h3 id="_1、监听函数"><a href="#_1、监听函数" class="header-anchor">#</a> 1、监听函数</h3> <p>浏览器的事件模型，就是通过监听函数（listener）对事件做出反应。事件发生后，浏览器监听到了这个事件，就会执行对应的监听函数。这是事件驱动编程模式（event-driven）的主要编程方式。</p> <p>JavaScript 有三种方法，可以为事件绑定监听函数。</p> <h4 id="_1-2-html-的-on-属性"><a href="#_1-2-html-的-on-属性" class="header-anchor">#</a> 1.2 HTML 的 on- 属性</h4> <p>HTML 语言允许在元素的属性中，直接定义某些事件的监听代码。</p> <div class="language-html line-numbers-mode"><pre class="language-html"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>body</span> <span class="token special-attr"><span class="token attr-name">onload</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span><span class="token value javascript language-javascript"><span class="token function">doSomething</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span><span class="token punctuation">&quot;</span></span></span><span class="token punctuation">&gt;</span></span> <span class="token comment">&lt;!-- 加圆括号--&gt;</span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token special-attr"><span class="token attr-name">onclick</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span><span class="token value javascript language-javascript">console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'触发事件'</span><span class="token punctuation">)</span></span><span class="token punctuation">&quot;</span></span></span><span class="token punctuation">&gt;</span></span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br></div></div><p>上面代码为<code>body</code>节点的<code>load</code>事件、<code>div</code>节点的<code>click</code>事件，指定了监听代码。一旦事件发生，就会执行这段代码。</p> <p>元素的事件监听属性，都是<code>on</code>加上事件名，比如<code>onload</code>就是<code>on + load</code>，表示<code>load</code>事件的监听代码。</p> <p>注意，这些属性的值是将会执行的代码，而不是一个函数。</p> <div class="language-html line-numbers-mode"><pre class="language-html"><code><span class="token comment">&lt;!-- 正确 --&gt;</span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>body</span> <span class="token special-attr"><span class="token attr-name">onload</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span><span class="token value javascript language-javascript"><span class="token function">doSomething</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span><span class="token punctuation">&quot;</span></span></span><span class="token punctuation">&gt;</span></span>

<span class="token comment">&lt;!-- 错误 --&gt;</span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>body</span> <span class="token special-attr"><span class="token attr-name">onload</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span><span class="token value javascript language-javascript">doSomething</span><span class="token punctuation">&quot;</span></span></span><span class="token punctuation">&gt;</span></span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br></div></div><p>一旦指定的事件发生，<code>on-</code>属性的值是原样传入 JavaScript 引擎执行。因此如果要执行函数，<strong>不要忘记加上一对圆括号</strong>。</p> <p>使用这个方法指定的监听代码，只会在<strong>冒泡阶段触发</strong>。</p> <div class="language-html line-numbers-mode"><pre class="language-html"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token special-attr"><span class="token attr-name">onClick</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span><span class="token value javascript language-javascript">console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span></span><span class="token punctuation">&quot;</span></span></span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token special-attr"><span class="token attr-name">onClick</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span><span class="token value javascript language-javascript">console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span></span><span class="token punctuation">&quot;</span></span></span><span class="token punctuation">&gt;</span></span>点击<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br></div></div><p>上面代码中，<code>&lt;button&gt;</code>是<code>&lt;div&gt;</code>的子元素。<code>&lt;button&gt;</code>的<code>click</code>事件，也会触发<code>&lt;div&gt;</code>的<code>click</code>事件。由于<code>on-</code>属性的监听代码，只在冒泡阶段触发，所以点击结果是先输出<code>1</code>，再输出<code>2</code>，即事件<strong>从子元素开始冒泡到父元素。</strong></p> <p>直接设置<code>on-</code>属性，与通过元素节点的<code>setAttribute</code>方法设置<code>on-</code>属性，效果是一样的。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code>el<span class="token punctuation">.</span><span class="token function">setAttribute</span><span class="token punctuation">(</span><span class="token string">'onclick'</span><span class="token punctuation">,</span> <span class="token string">'doSomething()'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 等同于</span>
<span class="token comment">// &lt;Element onclick=&quot;doSomething()&quot;&gt;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br></div></div><h4 id="_1-2-元素节点的事件属性-例-el-onclick"><a href="#_1-2-元素节点的事件属性-例-el-onclick" class="header-anchor">#</a> 1.2 元素节点的事件属性 (例：el.onclick)</h4> <p>元素节点对象的<strong>事件属性</strong>，同样可以指定监听函数。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code>window<span class="token punctuation">.</span>onload <span class="token operator">=</span> doSomething<span class="token punctuation">;</span> <span class="token comment">// 注意这里是函数名，不加圆括号</span>

div<span class="token punctuation">.</span><span class="token function-variable function">onclick</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// onclick是元素的一个属性，它指向一个函数，在触发点击时执行此函数</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'触发事件'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br></div></div><p>使用这个方法指定的监听函数，也是只会在<strong>冒泡阶段触发</strong>。</p> <p>注意，这种方法与 HTML 的<code>on-</code>属性的差异是，它的值是函数名（<code>doSomething</code>），而不像后者，必须给出完整的监听代码（<code>doSomething()</code>）。</p> <h4 id="_1-3-eventtarget-addeventlistener"><a href="#_1-3-eventtarget-addeventlistener" class="header-anchor">#</a> 1.3 EventTarget.addEventListener()</h4> <p><strong>所有 DOM 节点实例都有<code>addEventListener</code>方法</strong>，用来为该节点定义事件的监听函数。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code>window<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'load'</span><span class="token punctuation">,</span> doSomething<span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 注意这里是函数名，不加圆括号</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><p><code>addEventListener</code>方法的详细介绍，参见<code>EventTarget</code>章节。</p> <h4 id="_1-4-小结"><a href="#_1-4-小结" class="header-anchor">#</a> 1.4 小结</h4> <p>上面三种方法，</p> <p>第一种“HTML 的 on- 属性”，违反了 HTML 与 JavaScript 代码相分离的原则，将两者写在一起，不利于代码分工，因此<strong>不推荐使用</strong>。</p> <p>第二种“元素节点的事件属性”的<strong>缺点</strong>在于，<strong>同一个事件只能定义一个监听函数</strong>，也就是说，如果定义两次<code>onclick</code>属性，后一次定义会覆盖前一次。因此，<strong>也不推荐使用</strong>。</p> <p>第三种<code>EventTarget.addEventListener</code>是<strong>推荐的指定监听函数的方法</strong>。它有如下优点：</p> <ul><li>同一个事件可以添加多个监听函数。</li> <li>能够指定在哪个阶段（捕获阶段还是冒泡阶段）触发监听函数。</li> <li>除了 DOM 节点，其他对象（比如<code>window</code>、<code>XMLHttpRequest</code>等）也有这个接口，它等于是整个 JavaScript 统一的监听函数接口。</li></ul> <h3 id="_2、this-的指向-指向元素节点"><a href="#_2、this-的指向-指向元素节点" class="header-anchor">#</a> 2、this 的指向 （指向元素节点）</h3> <p><strong>监听函数内部的<code>this</code>指向触发事件的那个元素节点。（三种事件绑定的this全指向元素节点）</strong></p> <div class="language-html line-numbers-mode"><pre class="language-html"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>btn<span class="token punctuation">&quot;</span></span> <span class="token special-attr"><span class="token attr-name">onclick</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span><span class="token value javascript language-javascript">console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>id<span class="token punctuation">)</span></span><span class="token punctuation">&quot;</span></span></span><span class="token punctuation">&gt;</span></span>点击<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><p>执行上面代码，点击后会输出<code>btn</code>。</p> <p>其他两种监听函数的写法，<code>this</code>的指向也是如此。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token comment">// HTML 代码如下</span>
<span class="token comment">// &lt;button id=&quot;btn&quot;&gt;点击&lt;/button&gt;</span>
<span class="token keyword">var</span> btn <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'btn'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// 写法一</span>
btn<span class="token punctuation">.</span><span class="token function-variable function">onclick</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>id<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token comment">// 写法二</span>
btn<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span>
  <span class="token string">'click'</span><span class="token punctuation">,</span>
  <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>id<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token boolean">false</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br></div></div><p>上面两种写法，点击按钮以后也是输出<code>btn</code>。</p> <h3 id="_3、事件的传播-捕获、目标、冒泡"><a href="#_3、事件的传播-捕获、目标、冒泡" class="header-anchor">#</a> 3、事件的传播（捕获、目标、冒泡）</h3> <p>一个事件发生后，会<strong>在子元素和父元素之间传播</strong>（propagation）。这种传播分成三个阶段。</p> <ul><li><strong>第一阶段</strong>：从<code>window</code>对象传导到目标节点（上层传到底层），称为“<strong>捕获阶段</strong>”（capture phase）。</li> <li><strong>第二阶段</strong>：在目标节点上触发，称为“<strong>目标阶段</strong>”（target phase）。</li> <li><strong>第三阶段</strong>：从目标节点传导回<code>window</code>对象（从底层传回上层），称为“<strong>冒泡阶段</strong>”（bubbling phase）。</li></ul> <p>这种三阶段的传播模型，使得同一个事件会在多个节点上触发。</p> <div class="language-html line-numbers-mode"><pre class="language-html"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span>点击<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br></div></div><p>上面代码中，<code>&lt;div&gt;</code>节点之中有一个<code>&lt;p&gt;</code>节点。</p> <p>如果对这两个节点，都设置<code>click</code>事件的监听函数（每个节点的捕获阶段和冒泡阶段，各设置一个监听函数），共计设置四个监听函数。然后，对<code>&lt;p&gt;</code>点击，<code>click</code>事件会触发四次。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token keyword">var</span> phases <span class="token operator">=</span> <span class="token punctuation">{</span>
  <span class="token number">1</span><span class="token operator">:</span> <span class="token string">'capture'</span><span class="token punctuation">,</span>
  <span class="token number">2</span><span class="token operator">:</span> <span class="token string">'target'</span><span class="token punctuation">,</span>
  <span class="token number">3</span><span class="token operator">:</span> <span class="token string">'bubble'</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token keyword">var</span> div <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'div'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">var</span> p <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'p'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

div<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'click'</span><span class="token punctuation">,</span> callback<span class="token punctuation">,</span> <span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// true 表示在捕获阶段触发</span>
p<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'click'</span><span class="token punctuation">,</span> callback<span class="token punctuation">,</span> <span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// true 表示在捕获阶段触发</span>
div<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'click'</span><span class="token punctuation">,</span> callback<span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">// fasle 表示在冒泡阶段触发</span>
p<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'click'</span><span class="token punctuation">,</span> callback<span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// fasle 表示在冒泡阶段触发</span>

<span class="token keyword">function</span> <span class="token function">callback</span><span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">var</span> tag <span class="token operator">=</span> event<span class="token punctuation">.</span>currentTarget<span class="token punctuation">.</span>tagName<span class="token punctuation">;</span> <span class="token comment">// 当前目标对象的标签名</span>
  <span class="token keyword">var</span> phase <span class="token operator">=</span> phases<span class="token punctuation">[</span>event<span class="token punctuation">.</span>eventPhase<span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token comment">// 触发的阶段</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">&quot;Tag: '&quot;</span> <span class="token operator">+</span> tag <span class="token operator">+</span> <span class="token string">&quot;'. EventPhase: '&quot;</span> <span class="token operator">+</span> phase <span class="token operator">+</span> <span class="token string">&quot;'&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">// 点击以后的结果</span>
<span class="token comment">// Tag: 'DIV'. EventPhase: 'capture'  捕获阶段</span>
<span class="token comment">// Tag: 'P'. EventPhase: 'target' 目标阶段</span>
<span class="token comment">// Tag: 'P'. EventPhase: 'target' 目标阶段</span>
<span class="token comment">// Tag: 'DIV'. EventPhase: 'bubble' 冒泡阶段</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br></div></div><p>上面代码表示，<code>click</code>事件被触发了四次：<code>&lt;div&gt;</code>节点的捕获阶段和冒泡阶段各1次，<code>&lt;p&gt;</code>节点的目标阶段触发了2次。</p> <ol><li>捕获阶段：事件从<code>&lt;div&gt;</code>向<code>&lt;p&gt;</code>传播时，触发<code>&lt;div&gt;</code>的<code>click</code>事件；</li> <li>目标阶段：事件从<code>&lt;div&gt;</code>到达<code>&lt;p&gt;</code>时，触发<code>&lt;p&gt;</code>的<code>click</code>事件；</li> <li>冒泡阶段：事件从<code>&lt;p&gt;</code>传回<code>&lt;div&gt;</code>时，再次触发<code>&lt;div&gt;</code>的<code>click</code>事件。</li></ol> <p>其中，<code>&lt;p&gt;</code>节点有两个监听函数（<code>addEventListener</code>方法第三个参数的不同，会导致绑定两个监听函数），因此它们都会因为<code>click</code>事件触发一次。所以，<code>&lt;p&gt;</code>会在<code>target</code>阶段有两次输出。</p> <p><strong>注意</strong>，<strong>浏览器总是假定<code>click</code>事件的目标节点，就是点击位置嵌套最深的那个节点</strong>（本例是<code>&lt;div&gt;</code>节点里面的<code>&lt;p&gt;</code>节点）。所以，<strong><code>&lt;p&gt;</code>节点的捕获阶段和冒泡阶段，都会显示为<code>target</code>阶段。</strong></p> <p>事件传播的最上层对象是<code>window</code>，接着依次是<code>document</code>，<code>html</code>（<code>document.documentElement</code>）和<code>body</code>（<code>document.body</code>）。也就是说，上例的事件传播顺序，在捕获阶段依次为<code>window</code>、<code>document</code>、<code>html</code>、<code>body</code>、<code>div</code>、<code>p</code>，在冒泡阶段依次为<code>p</code>、<code>div</code>、<code>body</code>、<code>html</code>、<code>document</code>、<code>window</code>。</p> <div class="language- line-numbers-mode"><pre class="language-text"><code>捕获阶段：
window(浏览器对象)--&gt; document(文档对象) --&gt; html --&gt; body --&gt; div --&gt; p (点击目标，在目标阶段)

冒泡阶段：
p (点击目标，在目标阶段)--&gt; div --&gt; body --&gt; html --&gt; document(文档对象) --&gt; window(浏览器对象)
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br></div></div><h3 id="_4、事件的代理"><a href="#_4、事件的代理" class="header-anchor">#</a> 4、事件的代理</h3> <p>由于事件会在冒泡阶段向上传播到父节点，因此可以把<strong>子节点的监听函数定义在父节点上，由父节点的监听函数统一处理多个子元素的事件。这种方法叫做事件的代理</strong>（delegation）。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token keyword">var</span> ul <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'ul'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

ul<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'click'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>event<span class="token punctuation">.</span>target<span class="token punctuation">.</span>tagName<span class="token punctuation">.</span><span class="token function">toLowerCase</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">===</span> <span class="token string">'li'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// 浏览器假定click嵌套最深的元素是目标元素</span>
    <span class="token comment">// some code</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br></div></div><p>上面代码中，<code>click</code>事件的监听函数定义在<code>&lt;ul&gt;</code>节点，但是实际上，它处理的是子节点<code>&lt;li&gt;</code>的<code>click</code>事件。这样做的好处是，只要定义一个监听函数，就能处理多个子节点的事件，而不用在每个<code>&lt;li&gt;</code>节点上定义监听函数。而且以后再添加子节点，监听函数依然有效。</p> <h5 id="阻止事件冒泡-event-stoppropagation"><a href="#阻止事件冒泡-event-stoppropagation" class="header-anchor">#</a> 阻止事件冒泡 event.stopPropagation()</h5> <p>如果希望事件到某个节点为止，不再传播，可以使用事件对象的<code>stopPropagation</code>方法。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token comment">// 事件传播到 p 元素后，就不再向下传播了</span>
p<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'click'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  event<span class="token punctuation">.</span><span class="token function">stopPropagation</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 该方法在事件对象event上</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// true表示在捕获阶段绑定事件监听函数</span>

<span class="token comment">// 事件冒泡到 p 元素后，就不再向上冒泡了</span>
p<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'click'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  event<span class="token punctuation">.</span><span class="token function">stopPropagation</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// false表示在冒泡阶段（默认值）绑定事件监听函数</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br></div></div><p>上面代码中，<code>stopPropagation</code>方法分别在捕获阶段和冒泡阶段，阻止了事件的传播。</p> <p>但是，<strong><code>stopPropagation</code>方法只会阻止事件的传播，不会阻止该事件触发<code>&lt;p&gt;</code>节点的其他<code>click</code>事件的监听函数</strong>。也就是说，不是彻底取消<code>click</code>事件。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code>p<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'click'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  event<span class="token punctuation">.</span><span class="token function">stopPropagation</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

p<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'click'</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment">// 会触发</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br></div></div><p>上面代码中，<code>p</code>元素绑定了两个<code>click</code>事件的监听函数。<code>stopPropagation</code>方法只能阻止这个事件的传播，不能取消这个事件，因此，第二个监听函数会触发。输出结果会先是1，然后是2。</p> <p>如果<strong>想要彻底取消该事件</strong>，不再触发后面所有<code>click</code>的监听函数，<strong>可以使用<code>stopImmediatePropagation()</code>方法</strong>。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code>p<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'click'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  event<span class="token punctuation">.</span><span class="token function">stopImmediatePropagation</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

p<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'click'</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment">// 不会被触发</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br></div></div><p>上面代码中，<code>stopImmediatePropagation</code>方法可以彻底取消这个事件，使得后面绑定的所有<code>click</code>监听函数都不再触发。所以，只会输出1，不会输出2。</p> <h2 id="三、event-对象"><a href="#三、event-对象" class="header-anchor">#</a> 三、Event 对象</h2> <h3 id="_1-概述"><a href="#_1-概述" class="header-anchor">#</a> 1. 概述</h3> <p><strong>事件发生以后，会产生一个事件对象，作为参数传给监听函数</strong>。浏览器原生提供一个<code>Event</code>对象，所有的事件都是这个对象的实例，或者说继承了<code>Event.prototype</code>对象。</p> <p><strong><code>Event</code>对象本身就是一个构造函数，可以用来生成新的实例</strong>。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code>event <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Event</span><span class="token punctuation">(</span>type<span class="token punctuation">,</span> options<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">// 参数一，事件名称； 参数二，事件对象的配置对象</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><p><code>Event</code>构造函数接受两个参数。第一个参数<code>type</code>是字符串，表示事件的名称；第二个参数<code>options</code>是一个对象，表示事件对象的配置。该对象主要有下面两个属性。</p> <ul><li><code>bubbles</code>：布尔值，可选，默认为<code>false</code>，表示事件对象<strong>是否冒泡</strong>。</li> <li><code>cancelable</code>：布尔值，可选，默认为<code>false</code>，表示事件<strong>是否可以被取消</strong>，即能否用<code>Event.preventDefault()</code>取消这个事件。一旦事件被取消，就好像从来没有发生过，不会触发浏览器对该事件的默认行为。</li></ul> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token keyword">var</span> ev <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Event</span><span class="token punctuation">(</span> <span class="token comment">// 创建一个新的事件实例</span>
  <span class="token string">'look'</span><span class="token punctuation">,</span> <span class="token comment">// 事件名称</span>
  <span class="token punctuation">{</span> <span class="token comment">// 事件配置</span>
    <span class="token string-property property">'bubbles'</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token comment">// 事件是否冒泡</span>
    <span class="token string-property property">'cancelable'</span><span class="token operator">:</span> <span class="token boolean">false</span> <span class="token comment">// 事件是否可以被取消</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span>
document<span class="token punctuation">.</span><span class="token function">dispatchEvent</span><span class="token punctuation">(</span>ev<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 触发ev实例，该实例是look事件</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br></div></div><p>上面代码新建一个<code>look</code>事件实例，然后使用<code>dispatchEvent</code>方法触发该事件。</p> <p>注意，如果不是显式指定<code>bubbles</code>属性为<code>true</code>，生成的事件就只能在“捕获阶段”触发监听函数。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token comment">// HTML 代码为</span>
<span class="token comment">// &lt;div&gt;&lt;p&gt;Hello&lt;/p&gt;&lt;/div&gt;</span>
<span class="token keyword">var</span> div <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'div'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">var</span> p <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'p'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">function</span> <span class="token function">callback</span><span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">var</span> tag <span class="token operator">=</span> event<span class="token punctuation">.</span>currentTarget<span class="token punctuation">.</span>tagName<span class="token punctuation">;</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Tag: '</span> <span class="token operator">+</span> tag<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 没有任何输出</span>
<span class="token punctuation">}</span>

div<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'click'</span><span class="token punctuation">,</span> callback<span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 该事件是在冒泡阶段监听函数</span>

<span class="token keyword">var</span> click <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Event</span><span class="token punctuation">(</span><span class="token string">'click'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
p<span class="token punctuation">.</span><span class="token function">dispatchEvent</span><span class="token punctuation">(</span>click<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 给p发出一个click事件，该事件默认不会冒泡，因此不会触发父元素div的click事件</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br></div></div><p>上面代码中，<code>p</code>元素发出一个<code>click</code>事件，该事件默认不会冒泡。<code>div.addEventListener</code>方法指定在冒泡阶段监听，因此监听函数不会触发。如果写成<code>div.addEventListener('click', callback, true)</code>，那么在“捕获阶段”可以监听到这个事件。</p> <p>另一方面，如果这个事件在<code>div</code>元素上触发。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code>div<span class="token punctuation">.</span><span class="token function">dispatchEvent</span><span class="token punctuation">(</span>click<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><p>那么，不管<code>div</code>元素是在冒泡阶段监听，还是在捕获阶段监听，都会触发监听函数。因为这时<code>div</code>元素是事件的目标，不存在是否冒泡的问题，<code>div</code>元素总是会接收到事件，因此导致监听函数生效。</p> <h3 id="_2-实例属性"><a href="#_2-实例属性" class="header-anchor">#</a> 2. 实例属性</h3> <h4 id="_2-1-event-bubbles-是否会冒泡-只读-event-eventphase-返回整数-表示事件所处阶段-只读"><a href="#_2-1-event-bubbles-是否会冒泡-只读-event-eventphase-返回整数-表示事件所处阶段-只读" class="header-anchor">#</a> 2.1 Event.bubbles 是否会冒泡，只读，Event.eventPhase 返回整数，表示事件所处阶段，只读</h4> <p><code>Event.bubbles</code>属性<strong>返回一个布尔值，表示当前事件是否会冒泡</strong>。该属性为<strong>只读</strong>属性，一般用来了解 Event 实例是否可以冒泡。前面说过，除非显式声明，<code>Event</code>构造函数生成的事件，默认是不冒泡的。</p> <p><code>Event.eventPhase</code>属性<strong>返回一个整数常量，表示事件目前所处的阶段。该属性只读</strong>。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token keyword">var</span> phase <span class="token operator">=</span> event<span class="token punctuation">.</span>eventPhase<span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><p><code>Event.eventPhase</code>的返回值有四种可能。</p> <ul><li>0，事件目前<strong>没有发生</strong>。</li> <li>1，事件目前处于<strong>捕获阶段</strong>，即处于从祖先节点向目标节点的传播过程中。</li> <li>2，事件<strong>到达目标节点</strong>，即<code>Event.target</code>属性指向的那个节点。</li> <li>3，事件处于<strong>冒泡阶段</strong>，即处于从目标节点向祖先节点的反向传播过程中。</li></ul> <h4 id="_2-2-event-cancelable-是否可取消默认行为-event-cancelbubble是否阻止冒泡-event-defaultprevented-是否调用过取消默认行为方法"><a href="#_2-2-event-cancelable-是否可取消默认行为-event-cancelbubble是否阻止冒泡-event-defaultprevented-是否调用过取消默认行为方法" class="header-anchor">#</a> 2.2 Event.cancelable 是否可取消默认行为，Event.cancelBubble是否阻止冒泡，event.defaultPrevented 是否调用过取消默认行为方法</h4> <p><code>Event.cancelable</code>属性<strong>返回一个布尔值，表示事件是否可以取消</strong>。该属性为<strong>只读</strong>属性，一般用来了解 Event 实例的特性。</p> <p><strong>大多数浏览器的原生事件是可以取消的</strong>。比如，取消<code>click</code>事件，点击链接将无效。但是除非显式声明，<code>Event</code>构造函数生成的事件，<strong>默认是不可以取消的</strong>。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token keyword">var</span> evt <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Event</span><span class="token punctuation">(</span><span class="token string">'foo'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
evt<span class="token punctuation">.</span>cancelable  <span class="token comment">// false 默认不可取消</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br></div></div><p>当<code>Event.cancelable</code>属性为<code>true</code>时，调用<code>Event.preventDefault()</code>就可以取消这个事件，阻止浏览器对该事件的默认行为。</p> <p>如果事件不能取消，调用<code>Event.preventDefault()</code>会没有任何效果。所以使用这个方法之前，最好用<code>Event.cancelable</code>属性判断一下是否可以取消。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token keyword">function</span> <span class="token function">preventEvent</span><span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>event<span class="token punctuation">.</span>cancelable<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    event<span class="token punctuation">.</span><span class="token function">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
    console<span class="token punctuation">.</span><span class="token function">warn</span><span class="token punctuation">(</span><span class="token string">'This event couldn\'t be canceled.'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    console<span class="token punctuation">.</span><span class="token function">dir</span><span class="token punctuation">(</span>event<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br></div></div><p><code>Event.cancelBubble</code>属性是一个布尔值，如果设为<code>true</code>，相当于执行<code>Event.stopPropagation()</code>，可以<strong>阻止事件的传播。</strong></p> <p><code>Event.defaultPrevented</code>属性返回一个布尔值，表示该事件<strong>是否调用过<code>Event.preventDefault</code>方法。该属性只读。</strong></p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token keyword">if</span> <span class="token punctuation">(</span>event<span class="token punctuation">.</span>defaultPrevented<span class="token punctuation">)</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'该事件已经取消了'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br></div></div><h4 id="_2-3-event-currenttarget当前正在通过的节点-event-target目标节点"><a href="#_2-3-event-currenttarget当前正在通过的节点-event-target目标节点" class="header-anchor">#</a> 2.3 Event.currentTarget当前正在通过的节点，Event.target目标节点</h4> <p>事件发生以后，会经过捕获和冒泡两个阶段，依次通过多个 DOM 节点。因此，任意时点都有两个与事件相关的节点，一个是事件的<strong>原始触发节点</strong>（<code>Event.target</code>），另一个是事件<strong>当前正在通过的节点</strong>（<code>Event.currentTarget</code>）。<strong>前者通常是后者的后代节点</strong>。</p> <p><code>Event.currentTarget</code>属性返回事件<strong>当前所在的节点</strong>，即事件当前正在通过的节点，也就是当前正在执行的监听函数所在的那个节点。<strong>随着事件的传播，这个属性的值会变</strong>。</p> <p><code>Event.target</code>属性返回<strong>原始触发事件的那个节点</strong>，即事件最初发生的节点。这个属性不会随着事件的传播而改变。</p> <p>事件传播过程中，不同节点的监听函数内部的<code>Event.target</code>与<code>Event.currentTarget</code>属性的值是不一样的。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token comment">// HTML 代码为</span>
<span class="token comment">// &lt;p id=&quot;para&quot;&gt;Hello &lt;em&gt;World&lt;/em&gt;&lt;/p&gt;</span>
<span class="token keyword">function</span> <span class="token function">hide</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment">// 不管点击 Hello 或 World，总是返回 true</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">this</span> <span class="token operator">===</span> e<span class="token punctuation">.</span>currentTarget<span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token comment">// 点击 Hello，返回 true</span>
  <span class="token comment">// 点击 World，返回 false</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">this</span> <span class="token operator">===</span> e<span class="token punctuation">.</span>target<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'para'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'click'</span><span class="token punctuation">,</span> hide<span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br></div></div><p>上面代码中，<code>&lt;em&gt;</code>是<code>&lt;p&gt;</code>的子节点，点击<code>&lt;em&gt;</code>或者点击<code>&lt;p&gt;</code>，都会导致监听函数执行。这时，<code>e.target</code>总是指向原始点击位置的那个节点，而<code>e.currentTarget</code>指向事件传播过程中正在经过的那个节点。由于监听函数只有事件经过时才会触发，所以<code>e.currentTarget</code>总是等同于监听函数内部的<code>this</code>。</p> <h4 id="_2-4-event-type-事件类型-如-click"><a href="#_2-4-event-type-事件类型-如-click" class="header-anchor">#</a> 2.4 Event.type 事件类型（如：'click'）</h4> <p><code>Event.type</code>属性<strong>返回一个字符串，表示事件类型</strong>。事件的类型是在生成事件的时候指定的。该属性只读。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token keyword">var</span> evt <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Event</span><span class="token punctuation">(</span><span class="token string">'foo'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
evt<span class="token punctuation">.</span>type <span class="token comment">// &quot;foo&quot;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br></div></div><h4 id="_2-5-event-timestamp-相对于打开网页后的毫秒时间戳"><a href="#_2-5-event-timestamp-相对于打开网页后的毫秒时间戳" class="header-anchor">#</a> 2.5 Event.timeStamp 相对于打开网页后的毫秒时间戳</h4> <p><code>Event.timeStamp</code>属性返回一个毫秒时间戳，表示事件发生的时间。它是相对于网页加载成功开始计算的。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token keyword">var</span> evt <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Event</span><span class="token punctuation">(</span><span class="token string">'foo'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
evt<span class="token punctuation">.</span>timeStamp <span class="token comment">// 3683.6999999995896</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br></div></div><p>它的返回值有可能是整数，也有可能是小数（高精度时间戳），取决于浏览器的设置。</p> <p>下面是一个<strong>计算鼠标移动速度的例子</strong>，显示每秒移动的像素数量。</p> <h6 id="例子-计算鼠标移动速度"><a href="#例子-计算鼠标移动速度" class="header-anchor">#</a> 例子：计算鼠标移动速度</h6> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token keyword">var</span> previousX<span class="token punctuation">;</span>
<span class="token keyword">var</span> previousY<span class="token punctuation">;</span>
<span class="token keyword">var</span> previousT<span class="token punctuation">;</span>

window<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'mousemove'</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>
    previousX <span class="token operator">!==</span> <span class="token keyword">undefined</span> <span class="token operator">&amp;&amp;</span>
    previousY <span class="token operator">!==</span> <span class="token keyword">undefined</span> <span class="token operator">&amp;&amp;</span>
    previousT <span class="token operator">!==</span> <span class="token keyword">undefined</span>
  <span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">var</span> deltaX <span class="token operator">=</span> event<span class="token punctuation">.</span>screenX <span class="token operator">-</span> previousX<span class="token punctuation">;</span>
    <span class="token keyword">var</span> deltaY <span class="token operator">=</span> event<span class="token punctuation">.</span>screenY <span class="token operator">-</span> previousY<span class="token punctuation">;</span>
    <span class="token keyword">var</span> deltaD <span class="token operator">=</span> Math<span class="token punctuation">.</span><span class="token function">sqrt</span><span class="token punctuation">(</span>Math<span class="token punctuation">.</span><span class="token function">pow</span><span class="token punctuation">(</span>deltaX<span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">)</span> <span class="token operator">+</span> Math<span class="token punctuation">.</span><span class="token function">pow</span><span class="token punctuation">(</span>deltaY<span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">var</span> deltaT <span class="token operator">=</span> event<span class="token punctuation">.</span>timeStamp <span class="token operator">-</span> previousT<span class="token punctuation">;</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>deltaD <span class="token operator">/</span> deltaT <span class="token operator">*</span> <span class="token number">1000</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  previousX <span class="token operator">=</span> event<span class="token punctuation">.</span>screenX<span class="token punctuation">;</span>
  previousY <span class="token operator">=</span> event<span class="token punctuation">.</span>screenY<span class="token punctuation">;</span>
  previousT <span class="token operator">=</span> event<span class="token punctuation">.</span>timeStamp<span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br></div></div><h4 id="_2-6-event-istrusted-是否由真实用户行为产生的事件"><a href="#_2-6-event-istrusted-是否由真实用户行为产生的事件" class="header-anchor">#</a> 2.6 Event.isTrusted 是否由真实用户行为产生的事件</h4> <p><code>Event.isTrusted</code>属性返回一个<strong>布尔值</strong>，表示<strong>该事件是否由真实的用户行为产生</strong>。比如，用户点击链接会产生一个<code>click</code>事件，该事件是用户产生的；<code>Event</code>构造函数生成的事件，则是脚本产生的。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token keyword">var</span> evt <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Event</span><span class="token punctuation">(</span><span class="token string">'foo'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
evt<span class="token punctuation">.</span>isTrusted <span class="token comment">// false</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br></div></div><p>上面代码中，<code>evt</code>对象是脚本产生的，所以<code>isTrusted</code>属性返回<code>false</code>。</p> <h4 id="_2-7-event-detail-事件的细节-单击or双击等"><a href="#_2-7-event-detail-事件的细节-单击or双击等" class="header-anchor">#</a> 2.7 Event.detail 事件的细节（单击or双击等）</h4> <p><code>Event.detail</code>属性只有浏览器的 UI （用户界面）事件才具有。该属性返回一个数值，表示事件的某种信息。具体含义与事件类型相关。比如，对于<code>click</code>和<code>dblclick</code>事件，<code>Event.detail</code>是鼠标按下的次数（<code>1</code>表示单击，<code>2</code>表示双击，<code>3</code>表示三击）；对于鼠标滚轮事件，<code>Event.detail</code>是滚轮正向滚动的距离，负值就是负向滚动的距离，返回值总是3的倍数。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token comment">// HTML 代码如下</span>
<span class="token comment">// &lt;p&gt;Hello&lt;/p&gt;</span>
<span class="token keyword">function</span> <span class="token function">giveDetails</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>detail<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 快速点击的次数</span>
<span class="token punctuation">}</span>

document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'p'</span><span class="token punctuation">)</span><span class="token punctuation">.</span>onclick <span class="token operator">=</span> giveDetails<span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br></div></div><h3 id="_3、实例方法"><a href="#_3、实例方法" class="header-anchor">#</a> 3、实例方法</h3> <h4 id="_3-1-event-preventdefault-取消浏览器对当前事件的默认行为"><a href="#_3-1-event-preventdefault-取消浏览器对当前事件的默认行为" class="header-anchor">#</a> 3.1 Event.preventDefault()  取消浏览器对当前事件的默认行为</h4> <p><code>Event.preventDefault</code>方法<strong>取消浏览器对当前事件的默认行为</strong>。比如点击链接后，浏览器默认会跳转到另一个页面，使用这个方法以后，就不会跳转了；再比如，按一下空格键，页面向下滚动一段距离，使用这个方法以后也不会滚动了。该方法生效的前提是，事件对象的<code>cancelable</code>属性为<code>true</code>，如果为<code>false</code>，调用该方法没有任何效果。</p> <p><strong>注意，该方法只是取消事件对当前元素的默认影响，不会阻止事件的传播</strong>。如果要阻止传播，可以使用<code>stopPropagation()</code>或<code>stopImmediatePropagation()</code>方法。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token comment">// HTML 代码为</span>
<span class="token comment">// &lt;input type=&quot;checkbox&quot; id=&quot;my-checkbox&quot; /&gt;</span>
<span class="token keyword">var</span> cb <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'my-checkbox'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

cb<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span>
  <span class="token string">'click'</span><span class="token punctuation">,</span>
  <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span><span class="token punctuation">{</span> e<span class="token punctuation">.</span><span class="token function">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token boolean">false</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br></div></div><p>上面代码中，浏览器的默认行为是单击会选中单选框，取消这个行为，就导致无法选中单选框。</p> <p>利用这个方法，可以为文本输入框设置校验条件。如果用户的输入不符合条件，就无法将字符输入文本框。</p> <h6 id="例子-只能输入字母的输入框"><a href="#例子-只能输入字母的输入框" class="header-anchor">#</a> 例子：只能输入字母的输入框</h6> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token comment">// HTML 代码为</span>
<span class="token comment">// &lt;input type=&quot;text&quot; id=&quot;my-input&quot; /&gt;</span>
<span class="token keyword">var</span> input <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'my-input'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
input<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'keypress'</span><span class="token punctuation">,</span> checkName<span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">function</span> <span class="token function">checkName</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>e<span class="token punctuation">.</span>charCode <span class="token operator">&lt;</span> <span class="token number">97</span> <span class="token operator">||</span> e<span class="token punctuation">.</span>charCode <span class="token operator">&gt;</span> <span class="token number">122</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    e<span class="token punctuation">.</span><span class="token function">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br></div></div><p>上面代码为文本框的<code>keypress</code>事件设定监听函数后，将只能输入小写字母，否则输入事件的默认行为（写入文本框）将被取消，导致不能向文本框输入内容。</p> <h4 id="_3-2-event-stoppropagation-阻止事件传播"><a href="#_3-2-event-stoppropagation-阻止事件传播" class="header-anchor">#</a> 3.2 Event.stopPropagation() 阻止事件传播</h4> <p><code>stopPropagation</code>方法阻止事件在 DOM 中继续传播，防止再触发定义在别的节点上的监听函数，但是不包括在当前节点上其他的事件监听函数。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token keyword">function</span> <span class="token function">stopEvent</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  e<span class="token punctuation">.</span><span class="token function">stopPropagation</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 阻止事件冒泡</span>
<span class="token punctuation">}</span>

el<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'click'</span><span class="token punctuation">,</span> stopEvent<span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br></div></div><p>上面代码中，<code>click</code>事件将不会进一步冒泡到<code>el</code>节点的父节点。</p> <h4 id="_3-3-event-stopimmediatepropagation-阻止同一个事件的其他监听函数被调用"><a href="#_3-3-event-stopimmediatepropagation-阻止同一个事件的其他监听函数被调用" class="header-anchor">#</a> 3.3 Event.stopImmediatePropagation() 阻止同一个事件的其他监听函数被调用</h4> <p><code>Event.stopImmediatePropagation</code>方法阻止同一个事件的其他监听函数被调用，不管监听函数定义在当前节点还是其他节点。也就是说，该方法阻止事件的传播，比<code>Event.stopPropagation()</code>更彻底。</p> <p>如果同一个节点对于同一个事件指定了多个监听函数，这些函数会根据添加的顺序依次调用。只要其中有一个监听函数调用了<code>Event.stopImmediatePropagation</code>方法，其他的监听函数就不会再执行了。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token keyword">function</span> <span class="token function">l1</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
  e<span class="token punctuation">.</span><span class="token function">stopImmediatePropagation</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">function</span> <span class="token function">l2</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token comment">// 不会被调用</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'hello world'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

el<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'click'</span><span class="token punctuation">,</span> l1<span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
el<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'click'</span><span class="token punctuation">,</span> l2<span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br></div></div><p>上面代码在<code>el</code>节点上，为<code>click</code>事件添加了两个监听函数<code>l1</code>和<code>l2</code>。由于<code>l1</code>调用了<code>event.stopImmediatePropagation</code>方法，所以<code>l2</code>不会被调用。</p> <h4 id="_3-4-event-composedpath-数组-目标和冒泡的节点"><a href="#_3-4-event-composedpath-数组-目标和冒泡的节点" class="header-anchor">#</a> 3.4 Event.composedPath() 数组，目标和冒泡的节点</h4> <p><code>Event.composedPath()</code>返回一个数组，成员是事件的最底层节点和依次冒泡经过的所有上层节点。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token comment">// HTML 代码如下</span>
<span class="token comment">// &lt;div&gt;</span>
<span class="token comment">//   &lt;p&gt;Hello&lt;/p&gt;</span>
<span class="token comment">// &lt;/div&gt;</span>
<span class="token keyword">var</span> div <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'div'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">var</span> p <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'p'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

div<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'click'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span><span class="token function">composedPath</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// [p, div, body, html, document, Window]</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br></div></div><p>上面代码中，<code>click</code>事件的最底层节点是<code>p</code>，向上依次是<code>div</code>、<code>body</code>、<code>html</code>、<code>document</code>、<code>Window</code>。</p> <h2 id="四、鼠标事件"><a href="#四、鼠标事件" class="header-anchor">#</a> 四、鼠标事件</h2> <h3 id="_1、鼠标事件的种类"><a href="#_1、鼠标事件的种类" class="header-anchor">#</a> 1、鼠标事件的种类</h3> <p>鼠标事件指与鼠标相关的事件，继承了<code>MouseEvent</code>接口。具体的事件主要有以下一些。</p> <ul><li><code>click</code>：按下鼠标（通常是按下主按钮）时触发。<strong>【单击】</strong></li> <li><code>dblclick</code>：在同一个元素上双击鼠标时触发。<strong>【双击】</strong></li> <li><code>mousedown</code>：按下鼠标键时触发。<strong>【按下】</strong></li> <li><code>mouseup</code>：释放按下的鼠标键时触发。<strong>【抬起】</strong></li> <li><code>mousemove</code>：当鼠标在一个节点内部移动时触发。当鼠标持续移动时，该事件会连续触发。为了避免性能问题，建议对该事件的监听函数做一些限定，比如限定一段时间内只能运行一次。<strong>【经过（多次）】</strong></li> <li><code>mouseenter</code>：鼠标进入一个节点时触发，进入子节点不会触发这个事件（详见后文）。<strong>【进入（单次）】</strong></li> <li><code>mouseover</code>：鼠标进入一个节点时触发，进入子节点会再一次触发这个事件（详见后文）。<strong>【进入+子节点】</strong></li> <li><code>mouseleave</code>：鼠标离开一个节点时触发，离开父节点不会触发这个事件（详见后文）。<strong>【离开（单次）】</strong></li> <li><code>mouseout</code>：鼠标离开一个节点时触发，离开父节点会触发这个事件（详见后文）。<strong>【离开+子节点】</strong></li> <li><code>contextmenu</code>：按下鼠标右键时（上下文菜单出现前）触发，或者按下“上下文菜单键”时触发。<strong>【右键】</strong></li> <li><code>wheel</code>：滚动鼠标的滚轮时触发，该事件继承的是<code>WheelEvent</code>接口。<strong>【滚轮】</strong></li></ul> <p><code>click</code>事件指的是，用户在同一个位置先完成<code>mousedown</code>动作，再完成<code>mouseup</code>动作。因此，触发顺序是，<code>mousedown</code>首先触发，<code>mouseup</code>接着触发，<code>click</code>最后触发。</p> <p><code>dblclick</code>事件则会在<code>mousedown</code>、<code>mouseup</code>、<code>click</code>之后触发。</p> <p><code>mouseover</code>事件和<code>mouseenter</code>事件，都是鼠标进入一个节点时触发。两者的区别是，<code>mouseenter</code>事件只触发一次，而只要鼠标在节点内部移动，<code>mouseover</code>事件会在子节点上触发多次。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token comment">/* HTML 代码如下
 &lt;ul&gt;
   &lt;li&gt;item 1&lt;/li&gt;
   &lt;li&gt;item 2&lt;/li&gt;
  &lt;li&gt;item 3&lt;/li&gt;
 &lt;/ul&gt;
*/</span>

<span class="token keyword">var</span> ul <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'ul'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// 进入 ul 节点以后，mouseenter 事件只会触发一次</span>
<span class="token comment">// 以后只要鼠标在节点内移动，都不会再触发这个事件</span>
<span class="token comment">// event.target 是 ul 节点</span>
ul<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'mouseenter'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  event<span class="token punctuation">.</span>target<span class="token punctuation">.</span>style<span class="token punctuation">.</span>color <span class="token operator">=</span> <span class="token string">'purple'</span><span class="token punctuation">;</span>
  <span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    event<span class="token punctuation">.</span>target<span class="token punctuation">.</span>style<span class="token punctuation">.</span>color <span class="token operator">=</span> <span class="token string">''</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">500</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// 进入 ul 节点以后，只要在子节点上移动，mouseover 事件会触发多次</span>
<span class="token comment">// event.target 是 li 节点</span>
ul<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'mouseover'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  event<span class="token punctuation">.</span>target<span class="token punctuation">.</span>style<span class="token punctuation">.</span>color <span class="token operator">=</span> <span class="token string">'orange'</span><span class="token punctuation">;</span>
  <span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    event<span class="token punctuation">.</span>target<span class="token punctuation">.</span>style<span class="token punctuation">.</span>color <span class="token operator">=</span> <span class="token string">''</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">500</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br></div></div><p>上面代码中，在父节点内部进入子节点，不会触发<code>mouseenter</code>事件，但是会触发<code>mouseover</code>事件。</p> <p><code>mouseout</code>事件和<code>mouseleave</code>事件，都是鼠标离开一个节点时触发。两者的区别是，在父元素内部离开一个子元素时，<code>mouseleave</code>事件不会触发，而<code>mouseout</code>事件会触发。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token comment">/* HTML 代码如下
 &lt;ul&gt;
   &lt;li&gt;item 1&lt;/li&gt;
   &lt;li&gt;item 2&lt;/li&gt;
  &lt;li&gt;item 3&lt;/li&gt;
 &lt;/ul&gt;
*/</span>

<span class="token keyword">var</span> ul <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'ul'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// 先进入 ul 节点，然后在节点内部移动，不会触发 mouseleave 事件</span>
<span class="token comment">// 只有离开 ul 节点时，触发一次 mouseleave</span>
<span class="token comment">// event.target 是 ul 节点</span>
ul<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'mouseleave'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  event<span class="token punctuation">.</span>target<span class="token punctuation">.</span>style<span class="token punctuation">.</span>color <span class="token operator">=</span> <span class="token string">'purple'</span><span class="token punctuation">;</span>
  <span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    event<span class="token punctuation">.</span>target<span class="token punctuation">.</span>style<span class="token punctuation">.</span>color <span class="token operator">=</span> <span class="token string">''</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">500</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// 先进入 ul 节点，然后在节点内部移动，mouseout 事件会触发多次</span>
<span class="token comment">// event.target 是 li 节点</span>
ul<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'mouseout'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  event<span class="token punctuation">.</span>target<span class="token punctuation">.</span>style<span class="token punctuation">.</span>color <span class="token operator">=</span> <span class="token string">'orange'</span><span class="token punctuation">;</span>
  <span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    event<span class="token punctuation">.</span>target<span class="token punctuation">.</span>style<span class="token punctuation">.</span>color <span class="token operator">=</span> <span class="token string">''</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">500</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br></div></div><p>上面代码中，在父节点内部离开子节点，不会触发<code>mouseleave</code>事件，但是会触发<code>mouseout</code>事件。</p> <h3 id="_2、mouseevent-接口概述"><a href="#_2、mouseevent-接口概述" class="header-anchor">#</a> 2、MouseEvent 接口概述</h3> <p><code>MouseEvent</code>接口代表<strong>所有鼠标事件所产生的对象都是<code>MouseEvent</code>实例</strong>。此外，<strong>滚轮事件和拖拉事件也是<code>MouseEvent</code>实例。</strong></p> <p><code>MouseEvent</code>接口<strong>继承了<code>Event</code>接口</strong>，所以拥有<code>Event</code>的所有属性和方法。它还有自己的属性和方法。</p> <p>浏览器<strong>原生提供一个<code>MouseEvent</code>构造函数</strong>，用于新建一个<code>MouseEvent</code>实例。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token keyword">var</span> event <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">MouseEvent</span><span class="token punctuation">(</span>type<span class="token punctuation">,</span> options<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">// 参数一，事件名称字符串；参数二，事件配置对象</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><p><code>MouseEvent</code>构造函数接受两个参数。第一个参数是字符串，表示<strong>事件名称</strong>；第二个参数是一个<strong>事件配置对象</strong>，该参数可选。除了<code>Event</code>接口的实例配置属性，该对象可以配置以下属性，所有属性都是可选的。</p> <ul><li><code>screenX</code>：数值，鼠标相对于<strong>屏幕</strong>的水平位置（单位像素），默认值为0，设置该属性不会移动鼠标。</li> <li><code>screenY</code>：数值，鼠标相对于<strong>屏幕</strong>的垂直位置（单位像素），其他与<code>screenX</code>相同。</li> <li><code>clientX</code>：数值，鼠标相对于<strong>程序窗口</strong>的水平位置（单位像素），默认值为0，设置该属性不会移动鼠标。</li> <li><code>clientY</code>：数值，鼠标相对于<strong>程序窗口</strong>的垂直位置（单位像素），其他与<code>clientX</code>相同。</li> <li><code>ctrlKey</code>：布尔值，是否同时按下了 Ctrl 键，默认值为<code>false</code>。</li> <li><code>shiftKey</code>：布尔值，是否同时按下了 Shift 键，默认值为<code>false</code>。</li> <li><code>altKey</code>：布尔值，是否同时按下 Alt 键，默认值为<code>false</code>。</li> <li><code>metaKey</code>：布尔值，是否同时按下 Meta 键（win键），默认值为<code>false</code>。</li> <li><code>button</code>：数值，表示按下了哪一个鼠标按键，默认值为<code>0</code>，表示按下主键（通常是鼠标的左键）或者当前事件没有定义这个属性；<code>1</code>表示按下辅助键（通常是鼠标的中间键），<code>2</code>表示按下次要键（通常是鼠标的右键）。</li> <li><code>buttons</code>：数值，表示按下了鼠标的哪些键，是一个三个比特位的二进制值，默认为<code>0</code>（没有按下任何键）。<code>1</code>（二进制<code>001</code>）表示按下主键（通常是左键），<code>2</code>（二进制<code>010</code>）表示按下次要键（通常是右键），<code>4</code>（二进制<code>100</code>）表示按下辅助键（通常是中间键）。因此，如果返回<code>3</code>（二进制<code>011</code>）就表示同时按下了左键和右键。</li> <li><code>relatedTarget</code>：节点对象，表示事件的相关节点，默认为<code>null</code>。<code>mouseenter</code>和<code>mouseover</code>事件时，表示鼠标刚刚离开的那个元素节点；<code>mouseout</code>和<code>mouseleave</code>事件时，表示鼠标正在进入的那个元素节点。</li></ul> <p>下面是一个例子。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token keyword">var</span> event <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">MouseEvent</span><span class="token punctuation">(</span><span class="token string">'click2'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
    <span class="token string-property property">'bubbles'</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
    <span class="token string-property property">'cancelable'</span><span class="token operator">:</span> <span class="token boolean">true</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">var</span> cb <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'checkbox'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
cb<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'click2'</span><span class="token punctuation">,</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token comment">// 绑定事件监听函数</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token number">22</span><span class="token punctuation">)</span> <span class="token comment">// 被执行</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
cb<span class="token punctuation">.</span><span class="token function">dispatchEvent</span><span class="token punctuation">(</span>event<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">// 触发事件</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br></div></div><p>上面代码生成一个鼠标点击事件，并触发该事件。</p> <h3 id="_3、mouseevent-接口的实例属性"><a href="#_3、mouseevent-接口的实例属性" class="header-anchor">#</a> 3、MouseEvent 接口的实例属性</h3> <h4 id="_3-1-mouseevent-altkey-mouseevent-ctrlkey-mouseevent-metakey-mouseevent-shiftkey"><a href="#_3-1-mouseevent-altkey-mouseevent-ctrlkey-mouseevent-metakey-mouseevent-shiftkey" class="header-anchor">#</a> 3.1 MouseEvent.altKey，MouseEvent.ctrlKey，MouseEvent.metaKey，MouseEvent.shiftKey</h4> <p><code>MouseEvent.altKey</code>、<code>MouseEvent.ctrlKey</code>、<code>MouseEvent.metaKey</code>、<code>MouseEvent.shiftKey</code>这四个属性都返回一个布尔值，表示事件发生时，是否按下对应的键。它们都是<strong>只读</strong>属性。</p> <ul><li><code>altKey</code>属性：Alt 键</li> <li><code>ctrlKey</code>属性：Ctrl 键</li> <li><code>metaKey</code>属性：Meta 键（Mac 键盘是一个四瓣的小花，Windows 键盘是 Windows 键）</li> <li><code>shiftKey</code>属性：Shift 键</li></ul> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token comment">// HTML 代码如下</span>
<span class="token comment">// &lt;body onclick=&quot;showKey(event)&quot;&gt;</span>
<span class="token keyword">function</span> <span class="token function">showKey</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'ALT key pressed: '</span> <span class="token operator">+</span> e<span class="token punctuation">.</span>altKey<span class="token punctuation">)</span><span class="token punctuation">;</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'CTRL key pressed: '</span> <span class="token operator">+</span> e<span class="token punctuation">.</span>ctrlKey<span class="token punctuation">)</span><span class="token punctuation">;</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'META key pressed: '</span> <span class="token operator">+</span> e<span class="token punctuation">.</span>metaKey<span class="token punctuation">)</span><span class="token punctuation">;</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'SHIFT key pressed: '</span> <span class="token operator">+</span> e<span class="token punctuation">.</span>shiftKey<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br></div></div><p>上面代码中，点击网页会输出是否同时按下对应的键。</p> <h4 id="_3-2-mouseevent-button-鼠标的哪个键-mouseevent-buttons同时按哪些键"><a href="#_3-2-mouseevent-button-鼠标的哪个键-mouseevent-buttons同时按哪些键" class="header-anchor">#</a> 3.2 MouseEvent.button 鼠标的哪个键，MouseEvent.buttons同时按哪些键</h4> <p><code>MouseEvent.button</code>属性返回<strong>一个数值，表示事件发生时按下了鼠标的哪个键</strong>。该属性<strong>只读</strong>。</p> <ul><li>0：按下主键（通常是左键），或者该事件没有初始化这个属性（比如<code>mousemove</code>事件）。</li> <li>1：按下辅助键（通常是中键或者滚轮键）。</li> <li>2：按下次键（通常是右键）。</li></ul> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token comment">// HTML 代码为</span>
<span class="token comment">// &lt;button onmouseup=&quot;whichButton(event)&quot;&gt;点击&lt;/button&gt;</span>
<span class="token keyword">var</span> <span class="token function-variable function">whichButton</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">switch</span> <span class="token punctuation">(</span>e<span class="token punctuation">.</span>button<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">case</span> <span class="token number">0</span><span class="token operator">:</span>
      console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Left button clicked.'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword">break</span><span class="token punctuation">;</span>
    <span class="token keyword">case</span> <span class="token number">1</span><span class="token operator">:</span>
      console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Middle button clicked.'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword">break</span><span class="token punctuation">;</span>
    <span class="token keyword">case</span> <span class="token number">2</span><span class="token operator">:</span>
      console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Right button clicked.'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword">break</span><span class="token punctuation">;</span>
    <span class="token keyword">default</span><span class="token operator">:</span>
      console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Unexpected code: '</span> <span class="token operator">+</span> e<span class="token punctuation">.</span>button<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br></div></div><p><code>MouseEvent.buttons</code>属性返回一个<strong>三个比特位的值</strong>，表示<strong>同时按下了哪些键</strong>。它<strong>用来处理同时按下多个鼠标键的情况</strong>。该属性<strong>只读</strong>。</p> <ul><li>1：二进制为<code>001</code>（十进制的1），表示按下左键。</li> <li>2：二进制为<code>010</code>（十进制的2），表示按下右键。</li> <li>4：二进制为<code>100</code>（十进制的4），表示按下中键或滚轮键。</li></ul> <p>同时按下多个键的时候，每个按下的键对应的比特位都会有值。比如，同时按下左键和右键，会返回3（二进制为011）。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code>document<span class="token punctuation">.</span>body<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'mousemove'</span><span class="token punctuation">,</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token comment">// 注意，用click时一直都是0</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>buttons<span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token comment">// 未按下任何键时是 0</span>
<span class="token comment">// 按下左键 1  （001）</span>
<span class="token comment">// 按下右键 2  （010）</span>
<span class="token comment">// 按下中键 4  （100）</span>

<span class="token comment">// 按下左键和右键 3  （011）</span>
<span class="token comment">// 按下左键和中键 5  （101）</span>
<span class="token comment">// 按下右键和中键 6  （110）</span>
<span class="token comment">// 按下左、中、右键 7  （111）</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br></div></div><h4 id="_3-3-mouseevent-clientx-相对浏览器x坐标-mouseevent-clienty-相对浏览器y坐标"><a href="#_3-3-mouseevent-clientx-相对浏览器x坐标-mouseevent-clienty-相对浏览器y坐标" class="header-anchor">#</a> 3.3 MouseEvent.clientX 相对浏览器X坐标，MouseEvent.clientY 相对浏览器Y坐标</h4> <p><code>MouseEvent.clientX</code>属性返回鼠标位置相对于浏览器窗口左上角的水平坐标（单位像素），<code>MouseEvent.clientY</code>属性返回垂直坐标。这两个属性都是<strong>只读</strong>属性。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token comment">// HTML 代码为</span>
<span class="token comment">// &lt;body onmousedown=&quot;showCoords(event)&quot;&gt;</span>
<span class="token keyword">function</span> <span class="token function">showCoords</span><span class="token punctuation">(</span><span class="token parameter">evt</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>
    <span class="token string">'clientX value: '</span> <span class="token operator">+</span> evt<span class="token punctuation">.</span>clientX <span class="token operator">+</span> <span class="token string">'\n'</span> <span class="token operator">+</span>
    <span class="token string">'clientY value: '</span> <span class="token operator">+</span> evt<span class="token punctuation">.</span>clientY <span class="token operator">+</span> <span class="token string">'\n'</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br></div></div><p>这两个属性还分别有一个<strong>别名<code>MouseEvent.x</code>和<code>MouseEvent.y</code></strong>。</p> <h4 id="_3-4-mouseevent-movementx-上一个鼠标经过事件的x距离-mouseevent-movementy-上一个鼠标经过事件的y距离"><a href="#_3-4-mouseevent-movementx-上一个鼠标经过事件的x距离-mouseevent-movementy-上一个鼠标经过事件的y距离" class="header-anchor">#</a> 3.4 MouseEvent.movementX 上一个鼠标经过事件的X距离，MouseEvent.movementY 上一个鼠标经过事件的Y距离</h4> <p><code>MouseEvent.movementX</code>属性返回当前位置与上一个<code>mousemove</code>事件之间的水平距离（单位像素）。数值上，它等于下面的计算公式。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code>currentEvent<span class="token punctuation">.</span>movementX <span class="token operator">=</span> currentEvent<span class="token punctuation">.</span>screenX <span class="token operator">-</span> previousEvent<span class="token punctuation">.</span>screenX
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><p><code>MouseEvent.movementY</code>属性返回当前位置与上一个<code>mousemove</code>事件之间的垂直距离（单位像素）。数值上，它等于下面的计算公式。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code>currentEvent<span class="token punctuation">.</span>movementY <span class="token operator">=</span> currentEvent<span class="token punctuation">.</span>screenY <span class="token operator">-</span> previousEvent<span class="token punctuation">.</span>screenY。
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><p>这两个属性都是<strong>只读</strong>属性。</p> <h4 id="_3-5-mouseevent-screenx-相对屏幕x坐标-mouseevent-screeny-相对屏幕y坐标"><a href="#_3-5-mouseevent-screenx-相对屏幕x坐标-mouseevent-screeny-相对屏幕y坐标" class="header-anchor">#</a> 3.5 MouseEvent.screenX 相对屏幕X坐标，MouseEvent.screenY 相对屏幕Y坐标</h4> <p><code>MouseEvent.screenX</code>属性返回鼠标位置相对于屏幕左上角的水平坐标（单位像素），<code>MouseEvent.screenY</code>属性返回垂直坐标。这两个属性都是<strong>只读</strong>属性。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token comment">// HTML 代码如下</span>
<span class="token comment">// &lt;body onmousedown=&quot;showCoords(event)&quot;&gt;</span>
<span class="token keyword">function</span> <span class="token function">showCoords</span><span class="token punctuation">(</span><span class="token parameter">evt</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>
    <span class="token string">'screenX value: '</span> <span class="token operator">+</span> evt<span class="token punctuation">.</span>screenX <span class="token operator">+</span> <span class="token string">'\n'</span><span class="token punctuation">,</span>
    <span class="token string">'screenY value: '</span> <span class="token operator">+</span> evt<span class="token punctuation">.</span>screenY <span class="token operator">+</span> <span class="token string">'\n'</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br></div></div><h4 id="_3-6-mouseevent-offsetx-偏移量x-mouseevent-offsety-偏移量y"><a href="#_3-6-mouseevent-offsetx-偏移量x-mouseevent-offsety-偏移量y" class="header-anchor">#</a> 3.6 MouseEvent.offsetX 偏移量X，MouseEvent.offsetY 偏移量Y</h4> <p><code>MouseEvent.offsetX</code>属性返回鼠标位置与目标节点左侧的<code>padding</code>边缘的水平距离（单位像素），<code>MouseEvent.offsetY</code>属性返回与目标节点上方的<code>padding</code>边缘的垂直距离。这两个属性都是只读属性。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token comment">/* HTML 代码如下
  &lt;style&gt;
    p {
      width: 100px;
      height: 100px;
      padding: 100px;
    }
  &lt;/style&gt;
  &lt;p&gt;Hello&lt;/p&gt;
*/</span>
<span class="token keyword">var</span> p <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'p'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
p<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span>
  <span class="token string">'click'</span><span class="token punctuation">,</span>
  <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>offsetX<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 包含padding</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>offsetY<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token boolean">false</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br></div></div><p>上面代码中，鼠标如果在<code>p</code>元素的中心位置点击，会返回<code>150 150</code>。因此中心位置距离左侧和上方的<code>padding</code>边缘，等于<code>padding</code>的宽度（100像素）加上元素内容区域一半的宽度（50像素）。</p> <h4 id="_3-7-mouseevent-pagex-文档x坐标-mouseevent-pagey-文档y坐标"><a href="#_3-7-mouseevent-pagex-文档x坐标-mouseevent-pagey-文档y坐标" class="header-anchor">#</a> 3.7 MouseEvent.pageX 文档X坐标，MouseEvent.pageY 文档Y坐标</h4> <p><code>MouseEvent.pageX</code>属性返回鼠标位置与文档左侧边缘的距离（单位像素），<code>MouseEvent.pageY</code>属性返回与文档上侧边缘的距离（单位像素）。它们的<strong>返回值都包括文档不可见的部分</strong>。这两个属性都是<strong>只读</strong>。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token comment">/* HTML 代码如下
  &lt;style&gt;
    body {
      height: 2000px;
    }
  &lt;/style&gt;
*/</span>
document<span class="token punctuation">.</span>body<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span>
  <span class="token string">'click'</span><span class="token punctuation">,</span>
  <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>pageX<span class="token punctuation">)</span><span class="token punctuation">;</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>pageY<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token boolean">false</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br></div></div><p>上面代码中，页面高度为2000像素，会产生垂直滚动条。滚动到页面底部，点击鼠标输出的<code>pageY</code>值会接近2000。</p> <h4 id="_3-8-mouseevent-relatedtarget-事件的相关节点"><a href="#_3-8-mouseevent-relatedtarget-事件的相关节点" class="header-anchor">#</a> 3.8 MouseEvent.relatedTarget 事件的相关节点</h4> <p><code>MouseEvent.relatedTarget</code>属性<strong>返回事件的相关节点</strong>。对于那些没有相关节点的事件，该属性返回<code>null</code>。该属性<strong>只读</strong>。</p> <p>下表列出不同事件的<code>target</code>属性值和<code>relatedTarget</code>属性值义。</p> <table><thead><tr><th style="text-align:left;">事件名称</th> <th style="text-align:left;">target 属性</th> <th style="text-align:left;">relatedTarget 属性</th></tr></thead> <tbody><tr><td style="text-align:left;">focusin</td> <td style="text-align:left;">接受焦点的节点</td> <td style="text-align:left;">丧失焦点的节点</td></tr> <tr><td style="text-align:left;">focusout</td> <td style="text-align:left;">丧失焦点的节点</td> <td style="text-align:left;">接受焦点的节点</td></tr> <tr><td style="text-align:left;">mouseenter</td> <td style="text-align:left;">将要进入的节点</td> <td style="text-align:left;">将要离开的节点</td></tr> <tr><td style="text-align:left;">mouseleave</td> <td style="text-align:left;">将要离开的节点</td> <td style="text-align:left;">将要进入的节点</td></tr> <tr><td style="text-align:left;">mouseout</td> <td style="text-align:left;">将要离开的节点</td> <td style="text-align:left;">将要进入的节点</td></tr> <tr><td style="text-align:left;">mouseover</td> <td style="text-align:left;">将要进入的节点</td> <td style="text-align:left;">将要离开的节点</td></tr> <tr><td style="text-align:left;">dragenter</td> <td style="text-align:left;">将要进入的节点</td> <td style="text-align:left;">将要离开的节点</td></tr> <tr><td style="text-align:left;">dragexit</td> <td style="text-align:left;">将要离开的节点</td> <td style="text-align:left;">将要进入的节点</td></tr></tbody></table> <p>下面是一个例子。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token comment">/*
  HTML 代码如下
  &lt;div id=&quot;outer&quot; style=&quot;height:50px;width:50px;border-width:1px solid black;&quot;&gt;
    &lt;div id=&quot;inner&quot; style=&quot;height:25px;width:25px;border:1px solid black;&quot;&gt;&lt;/div&gt;
  &lt;/div&gt;
*/</span>

<span class="token keyword">var</span> inner <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'inner'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
inner<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'mouseover'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'进入'</span> <span class="token operator">+</span> event<span class="token punctuation">.</span>target<span class="token punctuation">.</span>id <span class="token operator">+</span> <span class="token string">' 离开'</span> <span class="token operator">+</span> event<span class="token punctuation">.</span>relatedTarget<span class="token punctuation">.</span>id<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
inner<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'mouseenter'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'进入'</span> <span class="token operator">+</span> event<span class="token punctuation">.</span>target<span class="token punctuation">.</span>id <span class="token operator">+</span> <span class="token string">' 离开'</span> <span class="token operator">+</span> event<span class="token punctuation">.</span>relatedTarget<span class="token punctuation">.</span>id<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
inner<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'mouseout'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'离开'</span> <span class="token operator">+</span> event<span class="token punctuation">.</span>target<span class="token punctuation">.</span>id <span class="token operator">+</span> <span class="token string">' 进入'</span> <span class="token operator">+</span> event<span class="token punctuation">.</span>relatedTarget<span class="token punctuation">.</span>id<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
inner<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">&quot;mouseleave&quot;</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'离开'</span> <span class="token operator">+</span> event<span class="token punctuation">.</span>target<span class="token punctuation">.</span>id <span class="token operator">+</span> <span class="token string">' 进入'</span> <span class="token operator">+</span> event<span class="token punctuation">.</span>relatedTarget<span class="token punctuation">.</span>id<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// 鼠标从 outer 进入inner，输出</span>
<span class="token comment">// 进入inner 离开outer</span>
<span class="token comment">// 进入inner 离开outer</span>

<span class="token comment">// 鼠标从 inner进入 outer，输出</span>
<span class="token comment">// 离开inner 进入outer</span>
<span class="token comment">// 离开inner 进入outer</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br></div></div><h3 id="_4、mouseevent-接口的实例方法"><a href="#_4、mouseevent-接口的实例方法" class="header-anchor">#</a> 4、MouseEvent 接口的实例方法</h3> <h4 id="_4-1-mouseevent-getmodifierstate-是否按下指定功能键"><a href="#_4-1-mouseevent-getmodifierstate-是否按下指定功能键" class="header-anchor">#</a> 4.1 MouseEvent.getModifierState() 是否按下指定功能键</h4> <p><code>MouseEvent.getModifierState</code>方法<strong>返回一个布尔值，表示有没有按下特定的功能键。它的参数是一个表示<a href="https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/getModifierState#Modifier_keys_on_Gecko" target="_blank" rel="noopener noreferrer">功能键<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a>的字符串。</strong></p> <div class="language-js line-numbers-mode"><pre class="language-js"><code>document<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'click'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span><span class="token function">getModifierState</span><span class="token punctuation">(</span><span class="token string">'CapsLock'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br></div></div><p>上面的代码可以了解用户是否按下了大写键。</p> <h3 id="_5、wheelevent-接口-滚轮"><a href="#_5、wheelevent-接口-滚轮" class="header-anchor">#</a> 5、WheelEvent 接口 （滚轮）</h3> <h4 id="_5-1-概述"><a href="#_5-1-概述" class="header-anchor">#</a> 5.1 概述</h4> <p><strong>WheelEvent 接口继承了 MouseEvent 实例，代表鼠标滚轮事件的实例对象</strong>。目前，鼠标滚轮相关的事件只有一个<code>wheel</code>事件，用户滚动鼠标的滚轮，就生成这个事件的实例。</p> <p>浏览器原生提供<code>WheelEvent()</code>构造函数，用来生成<code>WheelEvent</code>实例。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token keyword">var</span> wheelEvent <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">WheelEvent</span><span class="token punctuation">(</span>type<span class="token punctuation">,</span> options<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><p><code>WheelEvent()</code>构造函数可以接受两个参数，第一个是字符串，表示事件类型，对于滚轮事件来说，这个值目前只能是<code>wheel</code>。第二个参数是事件的配置对象。该对象的属性除了<code>Event</code>、<code>UIEvent</code>的配置属性以外，还可以接受以下几个属性，所有属性都是可选的。</p> <ul><li><code>deltaX</code>：数值，表示滚轮的水平滚动量，默认值是 0.0。</li> <li><code>deltaY</code>：数值，表示滚轮的垂直滚动量，默认值是 0.0。</li> <li><code>deltaZ</code>：数值，表示滚轮的 Z 轴滚动量，默认值是 0.0。</li> <li><code>deltaMode</code>：数值，表示相关的滚动事件的单位，适用于上面三个属性。<code>0</code>表示滚动单位为像素，<code>1</code>表示单位为行，<code>2</code>表示单位为页，默认为<code>0</code>。</li></ul> <h4 id="_5-2-实例属性"><a href="#_5-2-实例属性" class="header-anchor">#</a> 5.2 实例属性</h4> <p><code>WheelEvent</code>事件实例除了具有<code>Event</code>和<code>MouseEvent</code>的实例属性和实例方法，还有一些自己的实例属性，但是没有自己的实例方法。</p> <p>下面的属性都是只读属性。</p> <ul><li><code>WheelEvent.deltaX</code>：数值，表示滚轮的水平滚动量。</li> <li><code>WheelEvent.deltaY</code>：数值，表示滚轮的垂直滚动量。</li> <li><code>WheelEvent.deltaZ</code>：数值，表示滚轮的 Z 轴滚动量。</li> <li><code>WheelEvent.deltaMode</code>：数值，表示上面三个属性的单位，<code>0</code>是像素，<code>1</code>是行，<code>2</code>是页。</li></ul> <h2 id="五、键盘事件"><a href="#五、键盘事件" class="header-anchor">#</a> 五、键盘事件</h2> <h3 id="_1、键盘事件的种类"><a href="#_1、键盘事件的种类" class="header-anchor">#</a> 1、键盘事件的种类</h3> <p>键盘事件由用户击打键盘触发，主要有<code>keydown</code>、<code>keypress</code>、<code>keyup</code>三个事件，它们都继承了<code>KeyboardEvent</code>接口。</p> <ul><li><code>keydown</code>：按下键盘时触发。<strong>【按下】</strong></li> <li><code>keypress</code>：按下有值的键时触发，即按下 Ctrl、Alt、Shift、Meta 这样无值的键，这个事件不会触发。对于有值的键，按下时先触发<code>keydown</code>事件，再触发这个事件。<strong>【按下有值的键】</strong></li> <li><code>keyup</code>：松开键盘时触发该事件。<strong>【松开】</strong></li></ul> <p>如果用户一直按键不松开，就会连续触发键盘事件，触发的顺序如下。</p> <ol><li>keydown</li> <li>keypress</li> <li>keydown</li> <li>keypress</li> <li>...（重复以上过程）</li> <li>keyup</li></ol> <h3 id="_2、keyboardevent-接口概述"><a href="#_2、keyboardevent-接口概述" class="header-anchor">#</a> 2、KeyboardEvent 接口概述</h3> <p><code>KeyboardEvent</code>接口用来描述用户与键盘的互动。这个接口<strong>继承了<code>Event</code>接口</strong>，并且定义了自己的实例属性和实例方法。</p> <p>浏览器原生提供<code>KeyboardEvent</code>构造函数，用来新建键盘事件的实例。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token keyword">new</span> <span class="token class-name">KeyboardEvent</span><span class="token punctuation">(</span>type<span class="token punctuation">,</span> options<span class="token punctuation">)</span> <span class="token comment">// 参数一，事件类型；参数二，事件配置对象</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><p><code>KeyboardEvent</code>构造函数接受两个参数。第一个参数是字符串，表示<strong>事件类型</strong>；第二个参数是一个<strong>事件配置对象</strong>，该参数可选。除了<code>Event</code>接口提供的属性，还可以配置以下字段，它们都是可选。</p> <ul><li><code>key</code>：字符串，当前按下的键，默认为空字符串。<strong>【键名】</strong></li> <li><code>code</code>：字符串，表示当前按下的键的字符串形式，默认为空字符串。<strong>【键码】</strong></li> <li><code>location</code>：整数，当前按下的键的位置，默认为<code>0</code>。</li> <li><code>ctrlKey</code>：布尔值，是否按下 Ctrl 键，默认为<code>false</code>。</li> <li><code>shiftKey</code>：布尔值，是否按下 Shift 键，默认为<code>false</code>。</li> <li><code>altKey</code>：布尔值，是否按下 Alt 键，默认为<code>false</code>。</li> <li><code>metaKey</code>：布尔值，是否按下 Meta 键，默认为<code>false</code>。</li> <li><code>repeat</code>：布尔值，是否重复按键，默认为<code>false</code>。</li></ul> <h3 id="_3、keyboardevent-的实例属性"><a href="#_3、keyboardevent-的实例属性" class="header-anchor">#</a> 3、KeyboardEvent 的实例属性</h3> <h4 id="_3-1-keyboardevent-altkey-keyboardevent-ctrlkey-keyboardevent-metakey-keyboardevent-shiftkey-【是否按下对应键-布尔值】"><a href="#_3-1-keyboardevent-altkey-keyboardevent-ctrlkey-keyboardevent-metakey-keyboardevent-shiftkey-【是否按下对应键-布尔值】" class="header-anchor">#</a> 3.1 KeyboardEvent.altKey，KeyboardEvent.ctrlKey，KeyboardEvent.metaKey，KeyboardEvent.shiftKey 【是否按下对应键，布尔值】</h4> <p>以下属性都是<strong>只读</strong>属性，返回一个布尔值，表示是否按下对应的键。</p> <ul><li><code>KeyboardEvent.altKey</code>：是否按下 Alt 键</li> <li><code>KeyboardEvent.ctrlKey</code>：是否按下 Ctrl 键</li> <li><code>KeyboardEvent.metaKey</code>：是否按下 meta 键（Mac 系统是一个四瓣的小花，Windows 系统是 windows 键）</li> <li><code>KeyboardEvent.shiftKey</code>：是否按下 Shift 键</li></ul> <p>下面是一个示例。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token keyword">function</span> <span class="token function">showChar</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'ALT: '</span> <span class="token operator">+</span> e<span class="token punctuation">.</span>altKey<span class="token punctuation">)</span><span class="token punctuation">;</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'CTRL: '</span> <span class="token operator">+</span> e<span class="token punctuation">.</span>ctrlKey<span class="token punctuation">)</span><span class="token punctuation">;</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Meta: '</span> <span class="token operator">+</span> e<span class="token punctuation">.</span>metaKey<span class="token punctuation">)</span><span class="token punctuation">;</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Shift: '</span> <span class="token operator">+</span> e<span class="token punctuation">.</span>shiftKey<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

document<span class="token punctuation">.</span>body<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'keydown'</span><span class="token punctuation">,</span> showChar<span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br></div></div><h4 id="_3-2-keyboardevent-code-键码"><a href="#_3-2-keyboardevent-code-键码" class="header-anchor">#</a> 3.2 KeyboardEvent.code 键码</h4> <p><code>KeyboardEvent.code</code>属性<strong>返回一个字符串，表示当前按下的键的字符串形式</strong>。该属性<strong>只读</strong>。</p> <p>下面是一些常用键的字符串形式，其他键请查<a href="https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/code#Code_values" target="_blank" rel="noopener noreferrer">文档<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a>。</p> <ul><li>数字键0 - 9：返回<code>digital0</code> - <code>digital9</code></li> <li>字母键A - z：返回<code>KeyA</code> - <code>KeyZ</code></li> <li>功能键F1 - F12：返回 <code>F1</code> - <code>F12</code></li> <li>方向键：返回<code>ArrowDown</code>、<code>ArrowUp</code>、<code>ArrowLeft</code>、<code>ArrowRight</code></li> <li>Alt 键：返回<code>AltLeft</code>或<code>AltRight</code></li> <li>Shift 键：返回<code>ShiftLeft</code>或<code>ShiftRight</code></li> <li>Ctrl 键：返回<code>ControlLeft</code>或<code>ControlRight</code></li></ul> <h4 id="_3-3-keyboardevent-key-键名"><a href="#_3-3-keyboardevent-key-键名" class="header-anchor">#</a> 3.3 KeyboardEvent.key 键名</h4> <p><code>KeyboardEvent.key</code>属性<strong>返回一个字符串，表示按下的键名</strong>。该属性<strong>只读</strong>。</p> <p>如果按下的键代表可打印字符，则返回这个字符，比如数字、字母。</p> <p>如果按下的键代表不可打印的特殊字符，则返回预定义的键值，比如 Backspace，Tab，Enter，Shift，Control，Alt，CapsLock，Esc，Spacebar，PageUp，PageDown，End，Home，Left，Right，Up，Down，PrintScreen，Insert，Del，Win，F1～F12，NumLock，Scroll 等。</p> <p>如果同时按下一个控制键和一个符号键，则返回符号键的键名。比如，按下 Ctrl + a，则返回<code>a</code>；按下 Shift + a，则返回大写的<code>A</code>。</p> <p>如果无法识别键名，返回字符串<code>Unidentified</code>。</p> <h4 id="_3-4-keyboardevent-location-键处于哪个位置-整数"><a href="#_3-4-keyboardevent-location-键处于哪个位置-整数" class="header-anchor">#</a> 3.4 KeyboardEvent.location 键处于哪个位置，整数</h4> <p><code>KeyboardEvent.location</code>属性<strong>返回一个整数，表示按下的键处在键盘的哪一个区域</strong>。它可能取以下值。</p> <ul><li><p>0：处在键盘的主区域，或者无法判断处于哪一个区域。</p></li> <li><p>1：处在键盘的左侧，只适用那些有两个位置的键（比如 Ctrl 和 Shift 键）。</p></li> <li><p>2：处在键盘的右侧，只适用那些有两个位置的键（比如 Ctrl 和 Shift 键）。</p></li> <li><p>3：处在数字小键盘。</p></li></ul> <h4 id="_3-5-keyboardevent-repeat-是否长按"><a href="#_3-5-keyboardevent-repeat-是否长按" class="header-anchor">#</a> 3.5 KeyboardEvent.repeat 是否长按</h4> <p><code>KeyboardEvent.repeat</code>返回一个<strong>布尔值，代表该键是否被按着不放</strong>，以便判断是否重复这个键，即浏览器会持续触发<code>keydown</code>和<code>keypress</code>事件，直到用户松开手为止。</p> <h3 id="_4、keyboardevent-的实例方法"><a href="#_4、keyboardevent-的实例方法" class="header-anchor">#</a> 4、KeyboardEvent 的实例方法</h3> <h4 id="_4-1-keyboardevent-getmodifierstate-是否按下指定功能键"><a href="#_4-1-keyboardevent-getmodifierstate-是否按下指定功能键" class="header-anchor">#</a> 4.1 KeyboardEvent.getModifierState() 是否按下指定功能键</h4> <p><code>KeyboardEvent.getModifierState()</code>方法返回一个<strong>布尔值，表示是否按下或激活指定的功能键</strong>。它的常用参数如下。</p> <ul><li><code>Alt</code>：Alt 键</li> <li><code>CapsLock</code>：大写锁定键</li> <li><code>Control</code>：Ctrl 键</li> <li><code>Meta</code>：Meta 键</li> <li><code>NumLock</code>：数字键盘开关键</li> <li><code>Shift</code>：Shift 键</li></ul> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token keyword">if</span> <span class="token punctuation">(</span>
  event<span class="token punctuation">.</span><span class="token function">getModifierState</span><span class="token punctuation">(</span><span class="token string">'Control'</span><span class="token punctuation">)</span> <span class="token operator">+</span>
  event<span class="token punctuation">.</span><span class="token function">getModifierState</span><span class="token punctuation">(</span><span class="token string">'Alt'</span><span class="token punctuation">)</span> <span class="token operator">+</span>
  event<span class="token punctuation">.</span><span class="token function">getModifierState</span><span class="token punctuation">(</span><span class="token string">'Meta'</span><span class="token punctuation">)</span> <span class="token operator">&gt;</span> <span class="token number">1</span>
<span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br></div></div><p>上面代码表示，只要<code>Control</code>、<code>Alt</code>、<code>Meta</code>里面，同时按下任意两个或两个以上的键就返回。</p> <h2 id="六、进度事件"><a href="#六、进度事件" class="header-anchor">#</a> 六、进度事件</h2> <h3 id="_1、进度事件的种类"><a href="#_1、进度事件的种类" class="header-anchor">#</a> 1、进度事件的种类</h3> <p><strong>进度事件用来描述资源加载的进度</strong>，主要由 AJAX 请求、<code>&lt;img&gt;</code>、<code>&lt;audio&gt;</code>、<code>&lt;video&gt;</code>、<code>&lt;style&gt;</code>、<code>&lt;link&gt;</code>等外部资源的加载触发，继承了<code>ProgressEvent</code>接口。它主要包含以下几种<strong>事件</strong>。</p> <ul><li><code>abort</code>：外部资源中止加载时（比如用户取消）触发。如果发生错误导致中止，不会触发该事件。<strong>【中止加载】</strong></li> <li><code>error</code>：由于错误导致外部资源无法加载时触发。<strong>【加载错误】</strong></li> <li><code>load</code>：外部资源加载成功时触发。<strong>【加载成功】</strong></li> <li><code>loadstart</code>：外部资源开始加载时触发。<strong>【开始加载】</strong></li> <li><code>loadend</code>：外部资源停止加载时触发，发生顺序排在<code>error</code>、<code>abort</code>、<code>load</code>等事件的后面。<strong>【停止加载】</strong></li> <li><code>progress</code>：外部资源加载过程中不断触发。<strong>【加载中，不断触发】</strong></li> <li><code>timeout</code>：加载超时时触发。<strong>【加载超时】</strong></li></ul> <p>注意，除了资源下载，<strong>文件上传也存在这些事件</strong>。</p> <p>下面是一个例子。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code>image<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'load'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// 加载成功</span>
  image<span class="token punctuation">.</span>classList<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token string">'finished'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

image<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'error'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// 加载出错</span>
  image<span class="token punctuation">.</span>style<span class="token punctuation">.</span>display <span class="token operator">=</span> <span class="token string">'none'</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br></div></div><p>上面代码在图片元素加载完成后，为图片元素添加一个<code>finished</code>的 Class。如果加载失败，就把图片元素的样式设置为不显示。</p> <p>有时候，图片加载会在脚本运行之前就完成，尤其是当脚本放置在网页底部的时候，因此有可能<code>load</code>和<code>error</code>事件的监听函数根本不会执行。所以，比较可靠的方式，是用<code>complete</code>属性先判断一下是否加载完成。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token keyword">function</span> <span class="token function">loaded</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment">// ...</span>
<span class="token punctuation">}</span>

<span class="token keyword">if</span> <span class="token punctuation">(</span>image<span class="token punctuation">.</span>complete<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// 是否加载完成</span>
  <span class="token function">loaded</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
  image<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'load'</span><span class="token punctuation">,</span> loaded<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 加载成功事件</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br></div></div><p>由于 DOM 的元素节点没有提供是否加载错误的属性，所以<code>error</code>事件的监听函数最好放在<code>&lt;img&gt;</code>元素的 HTML 代码中，这样才能保证发生加载错误时百分之百会执行。</p> <div class="language-html line-numbers-mode"><pre class="language-html"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>img</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>/wrong/url<span class="token punctuation">&quot;</span></span> <span class="token special-attr"><span class="token attr-name">onerror</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span><span class="token value javascript language-javascript"><span class="token keyword">this</span><span class="token punctuation">.</span>style<span class="token punctuation">.</span>display<span class="token operator">=</span><span class="token string">'none'</span><span class="token punctuation">;</span></span><span class="token punctuation">&quot;</span></span></span> <span class="token punctuation">/&gt;</span></span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><p><code>loadend</code>事件的监听函数，可以用来取代<code>abort</code>事件、<code>load</code>事件、<code>error</code>事件的监听函数，因为它总是在这些事件之后发生。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code>req<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'loadend'</span><span class="token punctuation">,</span> loadEnd<span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">function</span> <span class="token function">loadEnd</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'传输结束，成功失败未知'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br></div></div><p><code>loadend</code>事件本身不提供关于进度结束的原因，但可以用它来做所有加载结束场景都需要做的一些操作。</p> <p>另外，<code>error</code>事件有一个特殊的性质，就是不会冒泡。所以，子元素的<code>error</code>事件，不会触发父元素的<code>error</code>事件监听函数。</p> <h3 id="_2、progressevent-接口"><a href="#_2、progressevent-接口" class="header-anchor">#</a> 2、ProgressEvent 接口</h3> <h4 id="_2-1-概述"><a href="#_2-1-概述" class="header-anchor">#</a> 2.1 概述</h4> <p><code>ProgressEvent</code>接口主要用来描述外部资源加载的进度，比如 AJAX 加载、<code>&lt;img&gt;</code>、<code>&lt;video&gt;</code>、<code>&lt;style&gt;</code>、<code>&lt;link&gt;</code>等外部资源加载。进度相关的事件都继承了这个接口。<strong>这个接口继承了Event接口。</strong></p> <p>浏览器原生提供了<code>ProgressEvent()</code>构造函数，用来生成事件实例。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token keyword">new</span> <span class="token class-name">ProgressEvent</span><span class="token punctuation">(</span>type<span class="token punctuation">,</span> options<span class="token punctuation">)</span> <span class="token comment">// 参数一，事件类型；参数二，配置对象</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><p><code>ProgressEvent()</code>构造函数接受两个参数。第一个参数是字符串，表示事件的类型，这个参数是必须的。第二个参数是一个配置对象，表示事件的属性，该参数可选。配置对象除了可以使用<code>Event</code>接口的配置属性，还可以使用下面的属性，所有这些属性都是可选的。</p> <ul><li><code>lengthComputable</code>：布尔值，表示加载的<strong>总量是否可以计算</strong>，默认是<code>false</code>。</li> <li><code>loaded</code>：整数，表示<strong>已经加载的量</strong>，默认是<code>0</code>。</li> <li><code>total</code>：整数，表示<strong>需要加载的总量</strong>，默认是<code>0</code>。</li></ul> <h4 id="_2-2-progressevent的实例属性。"><a href="#_2-2-progressevent的实例属性。" class="header-anchor">#</a> 2.2 ProgressEvent的实例属性。</h4> <ul><li><code>ProgressEvent.lengthComputable</code> <strong>总量是否可以计算</strong></li> <li><code>ProgressEvent.loaded</code> <strong>已加载的量</strong></li> <li><code>ProgressEvent.total</code> <strong>需要加载的总量</strong></li></ul> <p>如果<code>ProgressEvent.lengthComputable</code>为<code>false</code>，<code>ProgressEvent.total</code>实际上是没有意义的。</p> <p>下面是一个例子。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token keyword">var</span> p <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ProgressEvent</span><span class="token punctuation">(</span><span class="token string">'load'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
  <span class="token literal-property property">lengthComputable</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
  <span class="token literal-property property">loaded</span><span class="token operator">:</span> <span class="token number">30</span><span class="token punctuation">,</span>
  <span class="token literal-property property">total</span><span class="token operator">:</span> <span class="token number">100</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

document<span class="token punctuation">.</span>body<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'load'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'已经加载：'</span> <span class="token operator">+</span> <span class="token punctuation">(</span>e<span class="token punctuation">.</span>loaded <span class="token operator">/</span> e<span class="token punctuation">.</span>total<span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token number">100</span> <span class="token operator">+</span> <span class="token string">'%'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

document<span class="token punctuation">.</span>body<span class="token punctuation">.</span><span class="token function">dispatchEvent</span><span class="token punctuation">(</span>p<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 已经加载：30%</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br></div></div><p>上面代码先构造一个<code>load</code>事件，抛出后被监听函数捕捉到。</p> <p>下面是一个实际的例子。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token keyword">var</span> xhr <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">XMLHttpRequest</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

xhr<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'progress'</span><span class="token punctuation">,</span> updateProgress<span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 加载中</span>
xhr<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'load'</span><span class="token punctuation">,</span> transferComplete<span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 加载成功</span>
xhr<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'error'</span><span class="token punctuation">,</span> transferFailed<span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 加载错误</span>
xhr<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'abort'</span><span class="token punctuation">,</span> transferCanceled<span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 中止加载</span>

xhr<span class="token punctuation">.</span><span class="token function">open</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">function</span> <span class="token function">updateProgress</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// 加载中</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>e<span class="token punctuation">.</span>lengthComputable<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// 是否可以计算总量</span>
    <span class="token keyword">var</span> percentComplete <span class="token operator">=</span> e<span class="token punctuation">.</span>loaded <span class="token operator">/</span> e<span class="token punctuation">.</span>total<span class="token punctuation">;</span> <span class="token comment">// 加载进度计算</span>
  <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'不能计算进度'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token keyword">function</span> <span class="token function">transferComplete</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// 加载成功</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'传输结束'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">function</span> <span class="token function">transferFailed</span><span class="token punctuation">(</span><span class="token parameter">evt</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// 加载错误</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'传输过程中发生错误'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">function</span> <span class="token function">transferCanceled</span><span class="token punctuation">(</span><span class="token parameter">evt</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// 中止加载</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'用户取消了传输'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br></div></div><p>上面是下载过程的进度事件，还存在<strong>上传过程的进度事件</strong>。这时所有监听函数都要放在<code>XMLHttpRequest.upload</code>对象上面。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token keyword">var</span> xhr <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">XMLHttpRequest</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

xhr<span class="token punctuation">.</span>upload<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'progress'</span><span class="token punctuation">,</span> updateProgress<span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
xhr<span class="token punctuation">.</span>upload<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'load'</span><span class="token punctuation">,</span> transferComplete<span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
xhr<span class="token punctuation">.</span>upload<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'error'</span><span class="token punctuation">,</span> transferFailed<span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
xhr<span class="token punctuation">.</span>upload<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'abort'</span><span class="token punctuation">,</span> transferCanceled<span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

xhr<span class="token punctuation">.</span><span class="token function">open</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br></div></div><h2 id="七、表单事件"><a href="#七、表单事件" class="header-anchor">#</a> 七、表单事件</h2> <h3 id="_1、表单事件的种类"><a href="#_1、表单事件的种类" class="header-anchor">#</a> 1、表单事件的种类</h3> <h4 id="_1-1-input-事件-值发生变化触发-会连续"><a href="#_1-1-input-事件-值发生变化触发-会连续" class="header-anchor">#</a> 1.1 input 事件 （值发生变化触发，会连续）</h4> <p><code>input</code>事件当<code>&lt;input&gt;</code>、<code>&lt;select&gt;</code>、<code>&lt;textarea&gt;</code>的<strong>值发生变化时触发</strong>。对于复选框（<code>&lt;input type=checkbox&gt;</code>）或单选框（<code>&lt;input type=radio&gt;</code>），用户改变选项时，也会触发这个事件。另外，对于打开<code>contenteditable</code>属性的元素，只要值发生变化，也会触发<code>input</code>事件。</p> <p><code>input</code>事件的一个特点，就是<strong>会连续触发</strong>，比如<strong>用户每按下一次按键，就会触发一次<code>input</code>事件</strong>。</p> <p><code>input</code>事件对象<strong>继承了<code>InputEvent</code>接口</strong>。</p> <p>该事件跟<code>change</code>事件很像，不同之处在于**<code>input</code>事件在元素的值发生变化后立即发生**，<strong>而<code>change</code>在元素失去焦点时发生</strong>，而内容此时可能已经变化多次。也就是说，如果有连续变化，<strong><code>input</code>事件会触发多次，而<code>change</code>事件只在失去焦点时触发一次。</strong></p> <p>下面是<code>&lt;select&gt;</code>元素的例子。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token comment">/* HTML 代码如下
&lt;select id=&quot;mySelect&quot;&gt;
  &lt;option value=&quot;1&quot;&gt;1&lt;/option&gt;
  &lt;option value=&quot;2&quot;&gt;2&lt;/option&gt;
  &lt;option value=&quot;3&quot;&gt;3&lt;/option&gt;
&lt;/select&gt;
*/</span>

<span class="token keyword">function</span> <span class="token function">inputHandler</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">)</span>
<span class="token punctuation">}</span>

<span class="token keyword">var</span> mySelect <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'#mySelect'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
mySelect<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'input'</span><span class="token punctuation">,</span> inputHandler<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br></div></div><p>上面代码中，改变下拉框选项时，会触发<code>input</code>事件，从而执行回调函数<code>inputHandler</code>。</p> <h4 id="_1-2-select-事件-选中文本时触发"><a href="#_1-2-select-事件-选中文本时触发" class="header-anchor">#</a> 1.2 select 事件 （选中文本时触发）</h4> <p><code>select</code>事件当在<code>&lt;input&gt;</code>、<code>&lt;textarea&gt;</code>里面<strong>选中文本时触发</strong>。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token comment">// HTML 代码如下</span>
<span class="token comment">// &lt;input id=&quot;test&quot; type=&quot;text&quot; value=&quot;Select me!&quot; /&gt;</span>

<span class="token keyword">var</span> elem <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'test'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
elem<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'select'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>type<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// &quot;select&quot; 事件类型</span>

  <span class="token keyword">var</span> _target <span class="token operator">=</span> e<span class="token punctuation">.</span>target<span class="token punctuation">;</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>_target<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 文本框的全部值</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>_target<span class="token punctuation">.</span>selectionDirection<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 选择的方向：'forward'正向、'backward'反向</span>

  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>_target<span class="token punctuation">.</span>selectionStart<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 开始选择的索引</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>_target<span class="token punctuation">.</span>selectionEnd<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 结束选择的索引</span>
  <span class="token comment">// 注意：开始和结束索引是不分选择方向的，开始的索引一直是靠前的</span>

  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>_target<span class="token punctuation">.</span>value<span class="token punctuation">.</span><span class="token function">slice</span><span class="token punctuation">(</span>_target<span class="token punctuation">.</span>selectionStart<span class="token punctuation">,</span> _target<span class="token punctuation">.</span>selectionEnd<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">// 选中的那部分字符串</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br></div></div><p>选中的文本可以通过<code>event.target</code>元素的<code>selectionDirection</code>、<code>selectionEnd</code>、<code>selectionStart</code>和<code>value</code>属性拿到。</p> <h4 id="_1-3-change-事件-值发生变化时触发-单次"><a href="#_1-3-change-事件-值发生变化时触发-单次" class="header-anchor">#</a> 1.3 change 事件 （值发生变化时触发，单次）</h4> <p><code>change</code>事件当<code>&lt;input&gt;</code>、<code>&lt;select&gt;</code>、<code>&lt;textarea&gt;</code>的<strong>值发生变化时触发</strong>。它与<code>input</code>事件的最大不同，就是<strong>不会连续触发，只有当全部修改完成时才会触发</strong>，另一方面<code>input</code>事件必然伴随<code>change</code>事件。具体来说，分成以下几种情况。</p> <ul><li>激活单选框（radio）或复选框（checkbox）时触发。</li> <li>用户提交时触发。比如，从下列列表（select）完成选择，在日期或文件输入框完成选择。</li> <li>当文本框或<code>&lt;textarea&gt;</code>元素的值发生改变，并且丧失焦点时触发。</li></ul> <p>下面是一个例子。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token comment">// HTML 代码如下</span>
<span class="token comment">// &lt;select size=&quot;1&quot; onchange=&quot;changeEventHandler(event);&quot;&gt;</span>
<span class="token comment">//   &lt;option&gt;chocolate&lt;/option&gt;</span>
<span class="token comment">//   &lt;option&gt;strawberry&lt;/option&gt;</span>
<span class="token comment">//   &lt;option&gt;vanilla&lt;/option&gt;</span>
<span class="token comment">// &lt;/select&gt;</span>

<span class="token keyword">function</span> <span class="token function">changeEventHandler</span><span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>event<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br></div></div><p>如果比较一下上面<code>input</code>事件的例子，你会发现对于<code>&lt;select&gt;</code>元素来说，<code>input</code>和<code>change</code>事件基本是等价的。</p> <h4 id="_1-4-invalid-事件-表单提交不满足条件触发"><a href="#_1-4-invalid-事件-表单提交不满足条件触发" class="header-anchor">#</a> 1.4 invalid 事件 （表单提交不满足条件触发）</h4> <p><strong>用户提交表单时，如果表单元素的值不满足校验条件，就会触发<code>invalid</code>事件。</strong></p> <div class="language-html line-numbers-mode"><pre class="language-html"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>form</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>text<span class="token punctuation">&quot;</span></span> <span class="token attr-name">required</span> <span class="token attr-name">oninvalid</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>console.log(<span class="token punctuation">'</span>invalid input<span class="token punctuation">'</span>)<span class="token punctuation">&quot;</span></span> <span class="token punctuation">/&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>submit<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>提交<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>form</span><span class="token punctuation">&gt;</span></span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br></div></div><p>上面代码中，输入框是必填的。如果不填，用户点击按钮提交时，就会触发输入框的<code>invalid</code>事件，导致提交被取消。</p> <h4 id="_1-5-reset-事件-重置-submit-事件-提交"><a href="#_1-5-reset-事件-重置-submit-事件-提交" class="header-anchor">#</a> 1.5 reset 事件（重置），submit 事件（提交）</h4> <p><code>reset</code>事件当<strong>表单重置（所有表单成员变回默认值）时触发。</strong></p> <p><code>submit</code>事件当<strong>表单数据向服务器提交时触发</strong>。</p> <p>注意，<strong>这两个事件发生在表单对象<code>&lt;form&gt;</code>上，而不是发生在表单的成员上</strong>，因为提交的是表单，而不是表单成员。</p> <div class="language-html line-numbers-mode"><pre class="language-html"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>form</span> <span class="token special-attr"><span class="token attr-name">onreset</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span><span class="token value javascript language-javascript">console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'触发了重置事件'</span><span class="token punctuation">)</span></span><span class="token punctuation">&quot;</span></span></span> <span class="token special-attr"><span class="token attr-name">onsubmit</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span><span class="token value javascript language-javascript">console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'触发了提交事件'</span><span class="token punctuation">)</span></span><span class="token punctuation">&quot;</span></span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>input<span class="token punctuation">&quot;</span></span> <span class="token attr-name">action</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>html_form_action.php<span class="token punctuation">&quot;</span></span> <span class="token attr-name">method</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>get<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>text<span class="token punctuation">&quot;</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>lname<span class="token punctuation">&quot;</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>Duck<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>

    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>reset<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>重置<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>submit<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>提交<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>form</span><span class="token punctuation">&gt;</span></span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br></div></div><h3 id="_2、inputevent-接口-input事件的实例"><a href="#_2、inputevent-接口-input事件的实例" class="header-anchor">#</a> 2、InputEvent 接口（input事件的实例）</h3> <p><strong><code>InputEvent</code>接口主要用来描述<code>input</code>事件的实例</strong>。该接口<strong>继承了<code>Event</code>接口</strong>，还定义了一些自己的实例属性和实例方法。</p> <p>浏览器原生提供<code>InputEvent()</code>构造函数，用来生成实例对象。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token keyword">new</span> <span class="token class-name">InputEvent</span><span class="token punctuation">(</span>type<span class="token punctuation">,</span> options<span class="token punctuation">)</span> <span class="token comment">// 参数一，事件名称；参数二，配置对象</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><p><code>InputEvent</code>构造函数可以接受两个参数。第一个参数是字符串，表示<strong>事件名称</strong>，该参数是必需的。第二个参数是一个<strong>配置对象</strong>，用来设置事件实例的属性，该参数是可选的。配置对象的字段除了<code>Event</code>构造函数的配置属性，还可以设置下面的字段，这些字段都是可选的。</p> <ul><li><code>inputType</code>：字符串，表示<strong>发生变更的类型</strong>（详见下文）。</li> <li><code>data</code>：字符串，表示<strong>插入的字符串</strong>。如果没有插入的字符串（比如删除操作），则返回<code>null</code>或空字符串。</li> <li><code>dataTransfer</code>：返回一个 <strong>DataTransfer 对象实例，该属性通常只在输入框接受富文本输入时有效</strong>。</li></ul> <p><code>InputEvent</code>的实例属性主要就是上面三个属性，这三个实例属性都是<strong>只读的</strong>。</p> <h4 id="_1-inputevent-data-变动的那部分内容"><a href="#_1-inputevent-data-变动的那部分内容" class="header-anchor">#</a> （1）InputEvent.data 变动的那部分内容</h4> <p><code>InputEvent.data</code>属性返回一个字符串，表示<strong>变动的内容</strong>。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token comment">// HTML 代码如下</span>
<span class="token comment">// &lt;input type=&quot;text&quot; id=&quot;myInput&quot;&gt;</span>
<span class="token keyword">var</span> input <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'myInput'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
input<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'input'</span><span class="token punctuation">,</span> myFunction<span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">function</span> <span class="token function">myFunction</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>data<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br></div></div><p>上面代码中，如果手动在输入框里面输入<code>abc</code>，控制台会先输出<code>a</code>，再在下一行输出<code>b</code>，再在下一行输出<code>c</code>。然后选中<code>abc</code>，一次性将它们删除，控制台会输出<code>null</code>或一个空字符串。</p> <h4 id="_2-inputevent-inputtype-变更类型"><a href="#_2-inputevent-inputtype-变更类型" class="header-anchor">#</a> （2）InputEvent.inputType 变更类型</h4> <p><code>InputEvent.inputType</code>属性返回一个字符串，表示字符串<strong>发生变更的类型</strong>。</p> <p>对于常见情况，Chrome 浏览器的返回值如下。完整列表可以参考<a href="https://w3c.github.io/input-events/index.html#dom-inputevent-inputtype" target="_blank" rel="noopener noreferrer">文档<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a>。</p> <ul><li>手动插入文本：<code>insertText</code></li> <li>粘贴插入文本：<code>insertFromPaste</code></li> <li>向后删除：<code>deleteContentBackward</code></li> <li>向前删除：<code>deleteContentForward</code></li></ul> <h4 id="_3-inputevent-datatransfer"><a href="#_3-inputevent-datatransfer" class="header-anchor">#</a> （3）InputEvent.dataTransfer</h4> <p><code>InputEvent.dataTransfer</code>属性<strong>返回一个 DataTransfer 实例。该属性只在文本框接受粘贴内容（insertFromPaste）或拖拽内容（<code>insertFromDrop</code>）时才有效</strong>。</p> <h2 id="八、触摸事件"><a href="#八、触摸事件" class="header-anchor">#</a> 八、触摸事件</h2> <h3 id="_1、触摸操作概述"><a href="#_1、触摸操作概述" class="header-anchor">#</a> 1、触摸操作概述</h3> <p>浏览器的触摸 API 由三个部分组成。</p> <ul><li>Touch：一个触摸点的实例</li> <li>TouchList：多个触摸点集合的实例</li> <li>TouchEvent：触摸引发的事件实例</li></ul> <p><code>Touch</code>接口的实例对象用来表示触摸点（一根手指或者一根触摸笔），包括<strong>位置、大小、形状、压力、目标元素等属性</strong>。有时，触摸动作由多个触摸点（多根手指）组成，多个触摸点的集合由<code>TouchList</code>接口的实例对象表示。<code>TouchEvent</code>接口的实例对象代表由触摸引发的事件，只有触摸屏才会引发这一类事件。</p> <p>很多时候，<strong>触摸事件和鼠标事件同时触发</strong>，即使这个时候并没有用到鼠标。这是为了让那些只定义鼠标事件、没有定义触摸事件的代码，在触摸屏的情况下仍然能用。如果想避免这种情况，<strong>可以用<code>event.preventDefault</code>方法阻止发出鼠标事件</strong>。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code>TouchEvent <span class="token punctuation">{</span><span class="token literal-property property">isTrusted</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token literal-property property">touches</span><span class="token operator">:</span> TouchList<span class="token punctuation">,</span> <span class="token literal-property property">targetTouches</span><span class="token operator">:</span> TouchList<span class="token punctuation">,</span> <span class="token literal-property property">changedTouches</span><span class="token operator">:</span> TouchList<span class="token punctuation">,</span> <span class="token literal-property property">altKey</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span> …<span class="token punctuation">}</span> <span class="token comment">// TouchEvent接口 ，继承Event接口属性和方法</span>
    <span class="token literal-property property">altKey</span><span class="token operator">:</span> <span class="token boolean">false</span>
    <span class="token literal-property property">bubbles</span><span class="token operator">:</span> <span class="token boolean">true</span>
    <span class="token literal-property property">cancelBubble</span><span class="token operator">:</span> <span class="token boolean">false</span>
    <span class="token literal-property property">cancelable</span><span class="token operator">:</span> <span class="token boolean">false</span>
    <span class="token literal-property property">changedTouches</span><span class="token operator">:</span> TouchList <span class="token comment">// TouchList 接口 （所有触摸点集合）</span>
            <span class="token number">0</span><span class="token operator">:</span> Touch <span class="token comment">// Touch 接口 （单个触摸点）</span>
                <span class="token literal-property property">clientX</span><span class="token operator">:</span> <span class="token number">232</span>
                <span class="token literal-property property">clientY</span><span class="token operator">:</span> <span class="token number">96</span>
                <span class="token literal-property property">force</span><span class="token operator">:</span> <span class="token number">1</span> <span class="token comment">// 触摸压力</span>
                <span class="token literal-property property">identifier</span><span class="token operator">:</span> <span class="token number">0</span> <span class="token comment">// 唯一ID</span>
                <span class="token literal-property property">pageX</span><span class="token operator">:</span> <span class="token number">232</span>
                <span class="token literal-property property">pageY</span><span class="token operator">:</span> <span class="token number">96</span>
                <span class="token literal-property property">radiusX</span><span class="token operator">:</span> <span class="token number">11.5</span>
                <span class="token literal-property property">radiusY</span><span class="token operator">:</span> <span class="token number">11.5</span>
                <span class="token literal-property property">region</span><span class="token operator">:</span> <span class="token keyword">null</span>
                <span class="token literal-property property">rotationAngle</span><span class="token operator">:</span> <span class="token number">0</span>
                <span class="token literal-property property">screenX</span><span class="token operator">:</span> <span class="token number">476</span>
                <span class="token literal-property property">screenY</span><span class="token operator">:</span> <span class="token number">266</span>
                <span class="token literal-property property">target</span><span class="token operator">:</span> html <span class="token comment">// 触摸目标元素</span>
                <span class="token literal-property property">__proto__</span><span class="token operator">:</span> Touch
                <span class="token literal-property property">length</span><span class="token operator">:</span> <span class="token number">1</span>

    	<span class="token literal-property property">__proto__</span><span class="token operator">:</span> TouchList

    <span class="token literal-property property">composed</span><span class="token operator">:</span> <span class="token boolean">true</span>
    <span class="token literal-property property">ctrlKey</span><span class="token operator">:</span> <span class="token boolean">false</span>
    <span class="token literal-property property">currentTarget</span><span class="token operator">:</span> <span class="token keyword">null</span>
    <span class="token literal-property property">defaultPrevented</span><span class="token operator">:</span> <span class="token boolean">false</span>
    <span class="token literal-property property">detail</span><span class="token operator">:</span> <span class="token number">0</span>
    <span class="token literal-property property">eventPhase</span><span class="token operator">:</span> <span class="token number">0</span>
    <span class="token literal-property property">isTrusted</span><span class="token operator">:</span> <span class="token boolean">true</span>
    <span class="token literal-property property">metaKey</span><span class="token operator">:</span> <span class="token boolean">false</span>
    <span class="token literal-property property">path</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">)</span> <span class="token punctuation">[</span>html<span class="token punctuation">,</span> document<span class="token punctuation">,</span> Window<span class="token punctuation">]</span>
    <span class="token literal-property property">returnValue</span><span class="token operator">:</span> <span class="token boolean">true</span>
    <span class="token literal-property property">shiftKey</span><span class="token operator">:</span> <span class="token boolean">false</span>
    <span class="token literal-property property">sourceCapabilities</span><span class="token operator">:</span> InputDeviceCapabilities <span class="token punctuation">{</span><span class="token literal-property property">firesTouchEvents</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">}</span>
    <span class="token literal-property property">srcElement</span><span class="token operator">:</span> html
    <span class="token literal-property property">target</span><span class="token operator">:</span> html
    <span class="token literal-property property">targetTouches</span><span class="token operator">:</span> TouchList <span class="token punctuation">{</span><span class="token number">0</span><span class="token operator">:</span> Touch<span class="token punctuation">,</span> <span class="token literal-property property">length</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">}</span> <span class="token comment">// TouchList 接口 （所有触摸点集合）</span>
    <span class="token literal-property property">timeStamp</span><span class="token operator">:</span> <span class="token number">994.1749999998137</span>
    <span class="token literal-property property">touches</span><span class="token operator">:</span> TouchList <span class="token punctuation">{</span><span class="token number">0</span><span class="token operator">:</span> Touch<span class="token punctuation">,</span> <span class="token literal-property property">length</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">}</span> <span class="token comment">// TouchList 接口 （所有触摸点集合）</span>
    <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">&quot;touchmove&quot;</span> <span class="token comment">// 当前触摸事件类型</span>
    <span class="token literal-property property">view</span><span class="token operator">:</span> Window <span class="token punctuation">{</span><span class="token literal-property property">postMessage</span><span class="token operator">:</span> ƒ<span class="token punctuation">,</span> <span class="token literal-property property">blur</span><span class="token operator">:</span> ƒ<span class="token punctuation">,</span> <span class="token literal-property property">focus</span><span class="token operator">:</span> ƒ<span class="token punctuation">,</span> <span class="token literal-property property">close</span><span class="token operator">:</span> ƒ<span class="token punctuation">,</span> <span class="token literal-property property">parent</span><span class="token operator">:</span> Window<span class="token punctuation">,</span> …<span class="token punctuation">}</span>
    <span class="token literal-property property">which</span><span class="token operator">:</span> <span class="token number">0</span>

</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br><span class="line-number">31</span><br><span class="line-number">32</span><br><span class="line-number">33</span><br><span class="line-number">34</span><br><span class="line-number">35</span><br><span class="line-number">36</span><br><span class="line-number">37</span><br><span class="line-number">38</span><br><span class="line-number">39</span><br><span class="line-number">40</span><br><span class="line-number">41</span><br><span class="line-number">42</span><br><span class="line-number">43</span><br><span class="line-number">44</span><br><span class="line-number">45</span><br><span class="line-number">46</span><br></div></div><h3 id="_2、touch-接口"><a href="#_2、touch-接口" class="header-anchor">#</a> 2、Touch 接口</h3> <h4 id="_2-1-touch-接口概述-单个触摸点"><a href="#_2-1-touch-接口概述-单个触摸点" class="header-anchor">#</a> 2.1 Touch 接口概述 （单个触摸点）</h4> <p>Touch 接口<strong>代表单个触摸点</strong>。触摸点可能是一根手指，也可能是一根触摸笔。</p> <p>浏览器原生提供<code>Touch</code>构造函数，用来生成<code>Touch</code>实例。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token keyword">var</span> touch <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Touch</span><span class="token punctuation">(</span>touchOptions<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><p><code>Touch</code>构造函数接受一个<strong>配置对象作为参数</strong>，它有以下属性。</p> <ul><li><code>identifier</code>：必需，类型为整数，表示触摸点的唯一 ID。</li> <li><code>target</code>：必需，类型为元素节点，表示触摸点开始时所在的网页元素。</li> <li><code>clientX</code>：可选，类型为数值，表示触摸点相对于浏览器窗口左上角的水平距离，默认为0。</li> <li><code>clientY</code>：可选，类型为数值，表示触摸点相对于浏览器窗口左上角的垂直距离，默认为0。</li> <li><code>screenX</code>：可选，类型为数值，表示触摸点相对于屏幕左上角的水平距离，默认为0。</li> <li><code>screenY</code>：可选，类型为数值，表示触摸点相对于屏幕左上角的垂直距离，默认为0。</li> <li><code>pageX</code>：可选，类型为数值，表示触摸点相对于网页左上角的水平位置（即包括页面的滚动距离），默认为0。</li> <li><code>pageY</code>：可选，类型为数值，表示触摸点相对于网页左上角的垂直位置（即包括页面的滚动距离），默认为0。</li> <li><code>radiusX</code>：可选，类型为数值，表示触摸点周围受到影响的椭圆范围的 X 轴半径，默认为0。</li> <li><code>radiusY</code>：可选：类型为数值，表示触摸点周围受到影响的椭圆范围的 Y 轴半径，默认为0。</li> <li><code>rotationAngle</code>：可选，类型为数值，表示触摸区域的椭圆的旋转角度，单位为度数，在0到90度之间，默认值为0。</li> <li><code>force</code>：可选，类型为数值，范围在<code>0</code>到<code>1</code>之间，表示触摸压力。<code>0</code>代表没有压力，<code>1</code>代表硬件所能识别的最大压力，默认为<code>0</code>。</li></ul> <h4 id="_2-2-touch-接口的实例属性"><a href="#_2-2-touch-接口的实例属性" class="header-anchor">#</a> 2.2 Touch 接口的实例属性</h4> <h5 id="_1-touch-identifier-触摸点的id"><a href="#_1-touch-identifier-触摸点的id" class="header-anchor">#</a> （1）Touch.identifier 触摸点的ID</h5> <p><code>Touch.identifier</code>属性返回一个整数，表示触摸点的唯一 ID。这个值在整个触摸过程保持不变，直到触摸事件结束。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code>someElement<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'touchmove'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">var</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> e<span class="token punctuation">.</span>changedTouches<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>changedTouches<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span>identifier<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br></div></div><h5 id="_2-touch-screenx-touch-screeny-touch-clientx-touch-clienty-pagex-pagey-相对屏幕、浏览器、文档的坐标"><a href="#_2-touch-screenx-touch-screeny-touch-clientx-touch-clienty-pagex-pagey-相对屏幕、浏览器、文档的坐标" class="header-anchor">#</a> （2）Touch.screenX，Touch.screenY，Touch.clientX，Touch.clientY，pageX，pageY （相对屏幕、浏览器、文档的坐标）</h5> <p><code>Touch.screenX</code>属性和<code>Touch.screenY</code>属性，分别表示触摸点相对于屏幕左上角的横坐标和纵坐标，与页面是否滚动无关。</p> <p><code>Touch.clientX</code>属性和<code>Touch.clientY</code>属性，分别表示触摸点相对于浏览器视口左上角的横坐标和纵坐标，与页面是否滚动无关。</p> <p><code>Touch.pageX</code>属性和<code>Touch.pageY</code>属性，分别表示触摸点相对于当前页面左上角的横坐标和纵坐标，包含了页面滚动带来的位移。</p> <h5 id="_3-touch-radiusx-touch-radiusy-touch-rotationangle-触摸椭圆区域半径、角度"><a href="#_3-touch-radiusx-touch-radiusy-touch-rotationangle-触摸椭圆区域半径、角度" class="header-anchor">#</a> （3）Touch.radiusX，Touch.radiusY，Touch.rotationAngle （触摸椭圆区域半径、角度）</h5> <p><code>Touch.radiusX</code>属性和<code>Touch.radiusY</code>属性，分别返回<strong>触摸点周围受到影响的椭圆范围的 X 轴半径和 Y 轴半径，单位为像素。乘以 2 就可以得到触摸范围的宽度和高度</strong>。</p> <p><code>Touch.rotationAngle</code>属性表示触摸区域的椭圆的旋转角度，单位为度数，在<code>0</code>到<code>90</code>度之间。</p> <p>上面这三个属性共同定义了<strong>用户与屏幕接触的区域</strong>，对于描述手指这一类非精确的触摸，很有帮助。指尖接触屏幕，触摸范围会形成一个椭圆，这三个属性就用来描述这个椭圆区域。</p> <p>下面是一个示例。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code>div<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'touchstart'</span><span class="token punctuation">,</span> rotate<span class="token punctuation">)</span><span class="token punctuation">;</span>
div<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'touchmove'</span><span class="token punctuation">,</span> rotate<span class="token punctuation">)</span><span class="token punctuation">;</span>
div<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'touchend'</span><span class="token punctuation">,</span> rotate<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">function</span> <span class="token function">rotate</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">var</span> touch <span class="token operator">=</span> e<span class="token punctuation">.</span>changedTouches<span class="token punctuation">.</span><span class="token function">item</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  e<span class="token punctuation">.</span><span class="token function">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  src<span class="token punctuation">.</span>style<span class="token punctuation">.</span>width <span class="token operator">=</span> touch<span class="token punctuation">.</span>radiusX <span class="token operator">*</span> <span class="token number">2</span> <span class="token operator">+</span> <span class="token string">'px'</span><span class="token punctuation">;</span>
  src<span class="token punctuation">.</span>style<span class="token punctuation">.</span>height <span class="token operator">=</span> touch<span class="token punctuation">.</span>radiusY <span class="token operator">*</span> <span class="token number">2</span> <span class="token operator">+</span> <span class="token string">'px'</span><span class="token punctuation">;</span>
  src<span class="token punctuation">.</span>style<span class="token punctuation">.</span>transform <span class="token operator">=</span> <span class="token string">'rotate('</span> <span class="token operator">+</span> touch<span class="token punctuation">.</span>rotationAngle <span class="token operator">+</span> <span class="token string">'deg)'</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br></div></div><h5 id="_4-touch-force-触摸压力"><a href="#_4-touch-force-触摸压力" class="header-anchor">#</a> （4）Touch.force 触摸压力</h5> <p><code>Touch.force</code>属性返回一个<code>0</code>到<code>1</code>之间的数值，表示触摸压力。<code>0</code>代表没有压力，<code>1</code>代表硬件所能识别的最大压力。</p> <h5 id="_5-touch-target-开始触摸时的元素"><a href="#_5-touch-target-开始触摸时的元素" class="header-anchor">#</a> （5）Touch.target 开始触摸时的元素</h5> <p><code>Touch.target</code>属性返回一个元素节点，代表触摸发生时所在的那个元素节点。即使触摸点已经离开了这个节点，该属性依然不变。</p> <h3 id="_3、touchlist-接口"><a href="#_3、touchlist-接口" class="header-anchor">#</a> 3、TouchList 接口</h3> <p><code>TouchList</code>接口<strong>表示一组触摸点的集合</strong>。它的实例是一个<strong>类似数组的对象</strong>，成员是<code>Touch</code>的实例对象，表示所有触摸点。用户用三根手指触摸，产生的<code>TouchList</code>实例就会包含三个成员，每根手指的触摸点对应一个<code>Touch</code>实例对象。</p> <p>它的实例主要通过触摸事件的<code>TouchEvent.touches</code>、<code>TouchEvent.changedTouches</code>、<code>TouchEvent.targetTouches</code>这几个属性获取。</p> <p>它的实例属性和实例方法只有两个。</p> <ul><li><code>TouchList.length</code>：数值，表示成员数量（即触摸点的数量）。</li> <li><code>TouchList.item()</code>：返回指定位置的成员，它的参数是该成员的位置编号（从零开始）。</li></ul> <h3 id="_4、touchevent-接口"><a href="#_4、touchevent-接口" class="header-anchor">#</a> 4、TouchEvent 接口</h3> <h4 id="_4-1-概述"><a href="#_4-1-概述" class="header-anchor">#</a> 4.1 概述</h4> <p>TouchEvent 接口<strong>继承了 Event 接口</strong>，表示由<strong>触摸引发的事件实例</strong>，通常来自触摸屏或轨迹板。除了被继承的属性以外，它还有一些自己的属性。</p> <p>浏览器原生提供<code>TouchEvent()</code>构造函数，用来生成触摸事件的实例。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token keyword">new</span> <span class="token class-name">TouchEvent</span><span class="token punctuation">(</span>type<span class="token punctuation">,</span> options<span class="token punctuation">)</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><p><code>TouchEvent()</code>构造函数可以接受两个参数，第一个参数是字符串，表示事件类型；第二个参数是事件的配置对象，该参数是可选的，对象的所有属性也是可选的。除了<code>Event</code>接口的配置属性，该接口还有一些自己的配置属性。</p> <ul><li><code>touches</code>：<code>TouchList</code>实例，代表所有的当前处于活跃状态的触摸点，默认值是一个空数组<code>[]</code>。</li> <li><code>targetTouches</code>：<code>TouchList</code>实例，代表所有处在触摸的目标元素节点内部、且仍然处于活动状态的触摸点，默认值是一个空数组<code>[]</code>。</li> <li><code>changedTouches</code>：<code>TouchList</code>实例，代表本次触摸事件的相关触摸点，默认值是一个空数组<code>[]</code>。</li> <li><code>ctrlKey</code>：布尔值，表示 Ctrl 键是否同时按下，默认值为<code>false</code>。</li> <li><code>shiftKey</code>：布尔值，表示 Shift 键是否同时按下，默认值为<code>false</code>。</li> <li><code>altKey</code>：布尔值，表示 Alt 键是否同时按下，默认值为<code>false</code>。</li> <li><code>metaKey</code>：布尔值，表示 Meta 键（或 Windows 键）是否同时按下，默认值为<code>false</code>。</li></ul> <h4 id="_4-2-实例属性"><a href="#_4-2-实例属性" class="header-anchor">#</a> 4.2 实例属性</h4> <p>TouchEvent 接口的实例具有<code>Event</code>实例的所有属性和方法，此外还有一些它自己的实例属性，这些属性全部都是只读。</p> <h5 id="_1-touchevent-altkey-touchevent-ctrlkey-touchevent-shiftkey-touchevent-metakey-是否同时按某些功能键"><a href="#_1-touchevent-altkey-touchevent-ctrlkey-touchevent-shiftkey-touchevent-metakey-是否同时按某些功能键" class="header-anchor">#</a> （1）TouchEvent.altKey，TouchEvent.ctrlKey，TouchEvent.shiftKey，TouchEvent.metaKey （是否同时按某些功能键）</h5> <ul><li><code>TouchEvent.altKey</code>：布尔值，表示触摸时是否按下了 Alt 键。</li> <li><code>TouchEvent.ctrlKey</code>：布尔值，表示触摸时是否按下了 Ctrl 键。</li> <li><code>TouchEvent.shiftKey</code>：布尔值：表示触摸时是否按下了 Shift 键。</li> <li><code>TouchEvent.metaKey</code>：布尔值，表示触摸时是否按下了 Meta 键（或 Windows 键）。</li></ul> <p>下面是一个示例。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code>someElement<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'touchstart'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'altKey = '</span> <span class="token operator">+</span> e<span class="token punctuation">.</span>altKey<span class="token punctuation">)</span><span class="token punctuation">;</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'ctrlKey = '</span> <span class="token operator">+</span> e<span class="token punctuation">.</span>ctrlKey<span class="token punctuation">)</span><span class="token punctuation">;</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'metaKey = '</span> <span class="token operator">+</span> e<span class="token punctuation">.</span>metaKey<span class="token punctuation">)</span><span class="token punctuation">;</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'shiftKey = '</span> <span class="token operator">+</span> e<span class="token punctuation">.</span>shiftKey<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br></div></div><h5 id="_2-touchevent-changedtouches-触摸点集合-不同触摸事件-含义不同"><a href="#_2-touchevent-changedtouches-触摸点集合-不同触摸事件-含义不同" class="header-anchor">#</a> （2）TouchEvent.changedTouches （触摸点集合，不同触摸事件，含义不同）</h5> <p><code>TouchEvent.changedTouches</code>属性返回一个<code>TouchList</code>实例，成员是一组<code>Touch</code>实例对象，表示本次触摸事件的相关触摸点。</p> <p>对于<strong>不同的事件，该属性的含义有所不同。</strong></p> <ul><li><code>touchstart</code>事件：被激活的触摸点</li> <li><code>touchmove</code>事件：发生变化的触摸点</li> <li><code>touchend</code>事件：消失的触摸点（即不再被触碰的点）</li></ul> <p>下面是一个示例。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code>someElement<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'touchmove'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">var</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> e<span class="token punctuation">.</span>changedTouches<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>changedTouches<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span>identifier<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br></div></div><h5 id="_3-touchevent-touches-仍然活动的触摸点集合"><a href="#_3-touchevent-touches-仍然活动的触摸点集合" class="header-anchor">#</a> （3）TouchEvent.touches （仍然活动的触摸点集合）</h5> <p><code>TouchEvent.touches</code>属性返回一个<code>TouchList</code>实例，成员是所有<strong>仍然处于活动状态（即触摸中）的触摸点</strong>。一般来说，一个手指就是一个触摸点。</p> <p>下面是一个示例。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code>someElement<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'touchstart'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">switch</span> <span class="token punctuation">(</span>e<span class="token punctuation">.</span>touches<span class="token punctuation">.</span>length<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment">// 一根手指触摸</span>
    <span class="token keyword">case</span> <span class="token number">1</span><span class="token operator">:</span> <span class="token function">handle_one_touch</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">break</span><span class="token punctuation">;</span>
    <span class="token comment">// 两根手指触摸</span>
    <span class="token keyword">case</span> <span class="token number">2</span><span class="token operator">:</span> <span class="token function">handle_two_touches</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">break</span><span class="token punctuation">;</span>
    <span class="token comment">// 三根手指触摸</span>
    <span class="token keyword">case</span> <span class="token number">3</span><span class="token operator">:</span> <span class="token function">handle_three_touches</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">break</span><span class="token punctuation">;</span>
    <span class="token comment">// 其他情况</span>
    <span class="token keyword">default</span><span class="token operator">:</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Not supported'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">break</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br></div></div><h5 id="_4-touchevent-targettouches-目标元素内活动的触摸点集合"><a href="#_4-touchevent-targettouches-目标元素内活动的触摸点集合" class="header-anchor">#</a> （4）TouchEvent.targetTouches （目标元素内活动的触摸点集合）</h5> <p><code>TouchEvent.targetTouches</code>属性返回一个<code>TouchList</code>实例，成员是<strong>触摸事件的目标元素节点内部、所有仍然处于活动状态（即触摸中）的触摸点</strong>。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token keyword">function</span> <span class="token function">touches_in_target</span><span class="token punctuation">(</span><span class="token parameter">ev</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token punctuation">(</span>ev<span class="token punctuation">.</span>touches<span class="token punctuation">.</span>length <span class="token operator">===</span> ev<span class="token punctuation">.</span>targetTouches<span class="token punctuation">.</span>length <span class="token operator">?</span> <span class="token boolean">true</span> <span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br></div></div><p>上面代码用来判断，是否所有触摸点都在目标元素内。</p> <h3 id="_5、触摸事件的种类"><a href="#_5、触摸事件的种类" class="header-anchor">#</a> 5、触摸事件的种类</h3> <p>触摸引发的事件，有以下几种。可以通过<code>TouchEvent.type</code>属性，查看到底发生的是哪一种事件。</p> <ul><li><code>touchstart</code>：用户开始触摸时触发，它的<code>target</code>属性返回发生触摸的元素节点。<strong>【开始触摸】</strong></li> <li><code>touchend</code>：用户不再接触触摸屏时（或者移出屏幕边缘时）触发，它的<code>target</code>属性与<code>touchstart</code>事件一致的，就是开始触摸时所在的元素节点。它的<code>changedTouches</code>属性返回一个<code>TouchList</code>实例，包含所有不再触摸的触摸点（即<code>Touch</code>实例对象）。<strong>【触摸结束】</strong></li> <li><code>touchmove</code>：用户移动触摸点时触发，它的<code>target</code>属性与<code>touchstart</code>事件一致。如果触摸的半径、角度、力度发生变化，也会触发该事件。<strong>【触摸移动中】</strong></li> <li><code>touchcancel</code>：触摸点取消时触发，比如在触摸区域跳出一个模态窗口（modal window）、触摸点离开了文档区域（进入浏览器菜单栏）、用户的触摸点太多，超过了支持的上限（自动取消早先的触摸点）。<strong>【触摸点被取消】</strong></li></ul> <p>下面是一个例子。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token keyword">var</span> el <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementsByTagName</span><span class="token punctuation">(</span><span class="token string">'canvas'</span><span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
el<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'touchstart'</span><span class="token punctuation">,</span> handleStart<span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
el<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'touchmove'</span><span class="token punctuation">,</span> handleMove<span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">function</span> <span class="token function">handleStart</span><span class="token punctuation">(</span><span class="token parameter">evt</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  evt<span class="token punctuation">.</span><span class="token function">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">var</span> touches <span class="token operator">=</span> evt<span class="token punctuation">.</span>changedTouches<span class="token punctuation">;</span>
  <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">var</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> touches<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>touches<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span>pageX<span class="token punctuation">,</span> touches<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span>pageY<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token keyword">function</span> <span class="token function">handleMove</span><span class="token punctuation">(</span><span class="token parameter">evt</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  evt<span class="token punctuation">.</span><span class="token function">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">var</span> touches <span class="token operator">=</span> evt<span class="token punctuation">.</span>changedTouches<span class="token punctuation">;</span>
  <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">var</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> touches<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">var</span> touch <span class="token operator">=</span> touches<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">;</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>touch<span class="token punctuation">.</span>pageX<span class="token punctuation">,</span> touch<span class="token punctuation">.</span>pageY<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br></div></div><h2 id="九、拖拉事件"><a href="#九、拖拉事件" class="header-anchor">#</a> 九、拖拉事件</h2> <h3 id="_1、拖拉事件的种类"><a href="#_1、拖拉事件的种类" class="header-anchor">#</a> 1、拖拉事件的种类</h3> <p>拖拉（drag）指的是，<strong>用户在某个对象上按下鼠标键不放，拖动它到另一个位置，然后释放鼠标键，将该对象放在那里</strong>。</p> <p>拖拉的对象有好几种，包括<strong>元素节点、图片、链接、选中的文字等等</strong>。在网页中，除了元素节点默认不可以拖拉，其他（图片、链接、选中的文字）都是可以直接拖拉的。为了让元素节点可拖拉，可以将该节点的<code>draggable</code>属性设为<code>true</code>。</p> <div class="language-html line-numbers-mode"><pre class="language-html"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">draggable</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>true<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
  此区域可拖拉
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br></div></div><p><code>draggable</code>属性<strong>可用于任何元素节点</strong>，但是图片（<code>&lt;img&gt;</code>）和链接（<code>&lt;a&gt;</code>）不加这个属性，就可以拖拉。对于它们，用到这个属性的时候，往往是将其设为<code>false</code>，防止拖拉这两种元素。</p> <p><strong>注意</strong>，一旦某个元素节点的<code>draggable</code>属性设为<code>true</code>，<strong>就无法再用鼠标选中该节点内部的文字或子节点</strong>了。</p> <p>当元素节点或选中的文本被拖拉时，就<strong>会持续触发拖拉事件</strong>，包括以下一些事件。</p> <p><strong>拖拉的节点上触发：</strong></p> <ul><li><code>drag</code>：<strong>拖拉过程中</strong>，在被拖拉的节点上<strong>持续触发</strong>（相隔几百毫秒）。</li> <li><code>dragstart</code>：用户<strong>开始拖拉时</strong>，在被拖拉的节点上触发，该事件的<code>target</code>属性是被拖拉的节点。通常应该在这个事件的监听函数中，指定拖拉的数据。</li> <li><code>dragend</code>：<strong>拖拉结束时</strong>（释放鼠标键或按下 ESC 键）在被拖拉的节点上触发，该事件的<code>target</code>属性是被拖拉的节点。它与<code>dragstart</code>事件，在同一个节点上触发。不管拖拉是否跨窗口，或者中途被取消，<code>dragend</code>事件总是会触发的。</li></ul> <p><strong>拖拉到别的节点上触发：</strong></p> <ul><li><p><code>dragenter</code>：<strong>拖拉进入当前节点</strong>时，<strong>在当前节点上触发一次</strong>，该事件的<code>target</code>属性是当前节点。通常应该在这个事件的监听函数中，<strong>指定是否允许在当前节点放下（drop）拖拉的数据</strong>。如果当前节点没有该事件的监听函数，或者监听函数不执行任何操作，就意味着不允许在当前节点放下数据。在视觉上显示拖拉进入当前节点，也是在这个事件的监听函数中设置。</p></li> <li><p><code>dragover</code>：<strong>拖拉到当前节点上方时</strong>，在当前节点上<strong>持续触发</strong>（相隔几百毫秒），该事件的<code>target</code>属性是当前节点。该事件与<code>dragenter</code>事件的区别是，<code>dragenter</code>事件在进入该节点时触发，然后只要没有离开这个节点，<code>dragover</code>事件会持续触发。</p></li> <li><p><code>dragleave</code>：<strong>拖拉操作离开当前节点范围时</strong>，在当前节点上触发，该事件的<code>target</code>属性是当前节点。如果要在视觉上显示拖拉离开操作当前节点，就在这个事件的监听函数中设置。</p></li> <li><p><code>drop</code>：被拖拉的节点或选中的文本，<strong>释放到目标节点时，在目标节点上触发</strong>。注意，如果当前节点不允许<code>drop</code>，即使在该节点上方松开鼠标键，也不会触发该事件。如果用户按下 ESC 键，取消这个操作，也不会触发该事件。该事件的监听函数负责取出拖拉数据，并进行相关处理。</p></li></ul> <p>下面的例子展示，如何动态改变被拖动节点的背景色。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code>div<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'dragstart'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">this</span><span class="token punctuation">.</span>style<span class="token punctuation">.</span>backgroundColor <span class="token operator">=</span> <span class="token string">'red'</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

div<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'dragend'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">this</span><span class="token punctuation">.</span>style<span class="token punctuation">.</span>backgroundColor <span class="token operator">=</span> <span class="token string">'green'</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br></div></div><p>上面代码中，<code>div</code>节点被拖动时，背景色会变为红色，拖动结束，又变回绿色。</p> <div class="language-html line-numbers-mode"><pre class="language-html"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>div1<span class="token punctuation">&quot;</span></span> <span class="token attr-name">draggable</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>true<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
    div1，此区域可拖拉
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>div2<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
    div2
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span><span class="token punctuation">&gt;</span></span><span class="token script"><span class="token language-javascript">
    <span class="token keyword">var</span> div1 <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'.div1'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">var</span> div2 <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'.div2'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    div1<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'dragstart'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
        console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'开始拖拉'</span><span class="token punctuation">)</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    div1<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'drag'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'拖拉中'</span><span class="token punctuation">)</span> <span class="token comment">// 持续触发</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    div1<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'dragend'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
        console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'结束拖拉'</span><span class="token punctuation">)</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>


    div2<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'dragenter'</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
        console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'拖到了div2'</span><span class="token punctuation">)</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span>
    div2<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'dragover'</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
        <span class="token comment">//console.log('正在div2上方') // 持续触发</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span>
    div2<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'dragleave'</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
        console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'离开div2'</span><span class="token punctuation">)</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span>
    div2<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'drop'</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'在div2上释放'</span><span class="token punctuation">)</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span>
</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">&gt;</span></span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br><span class="line-number">31</span><br><span class="line-number">32</span><br><span class="line-number">33</span><br><span class="line-number">34</span><br><span class="line-number">35</span><br><span class="line-number">36</span><br></div></div><p>下面是一个例子，展示如何实现将一个节点从当前父节点，拖拉到另一个父节点中。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token comment">/* HTML 代码如下
 &lt;div class=&quot;dropzone&quot;&gt;
   &lt;div id=&quot;draggable&quot; draggable=&quot;true&quot;&gt;
     该节点可拖拉
   &lt;/div&gt;
 &lt;/div&gt;
 &lt;div class=&quot;dropzone&quot;&gt;&lt;/div&gt;
 &lt;div class=&quot;dropzone&quot;&gt;&lt;/div&gt;
 &lt;div class=&quot;dropzone&quot;&gt;&lt;/div&gt;
*/</span>

<span class="token comment">// 被拖拉节点</span>
<span class="token keyword">var</span> dragged<span class="token punctuation">;</span>

document<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'dragstart'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment">// 保存被拖拉节点</span>
  dragged <span class="token operator">=</span> event<span class="token punctuation">.</span>target<span class="token punctuation">;</span>
  <span class="token comment">// 被拖拉节点的背景色变透明</span>
  event<span class="token punctuation">.</span>target<span class="token punctuation">.</span>style<span class="token punctuation">.</span>opacity <span class="token operator">=</span> <span class="token number">0.5</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

document<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'dragend'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment">// 被拖拉节点的背景色恢复正常</span>
  event<span class="token punctuation">.</span>target<span class="token punctuation">.</span>style<span class="token punctuation">.</span>opacity <span class="token operator">=</span> <span class="token string">''</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

document<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'dragover'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment">// 防止拖拉效果被重置，允许被拖拉的节点放入目标节点</span>
  event<span class="token punctuation">.</span><span class="token function">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

document<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'dragenter'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment">// 目标节点的背景色变紫色</span>
  <span class="token comment">// 由于该事件会冒泡，所以要过滤节点</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>event<span class="token punctuation">.</span>target<span class="token punctuation">.</span>className <span class="token operator">===</span> <span class="token string">'dropzone'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    event<span class="token punctuation">.</span>target<span class="token punctuation">.</span>style<span class="token punctuation">.</span>background <span class="token operator">=</span> <span class="token string">'purple'</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

document<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'dragleave'</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span> <span class="token parameter">event</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment">// 目标节点的背景色恢复原样</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>event<span class="token punctuation">.</span>target<span class="token punctuation">.</span>className <span class="token operator">===</span> <span class="token string">'dropzone'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    event<span class="token punctuation">.</span>target<span class="token punctuation">.</span>style<span class="token punctuation">.</span>background <span class="token operator">=</span> <span class="token string">''</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

document<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'drop'</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span> <span class="token parameter">event</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment">// 防止事件默认行为（比如某些元素节点上可以打开链接），</span>
  event<span class="token punctuation">.</span><span class="token function">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>event<span class="token punctuation">.</span>target<span class="token punctuation">.</span>className <span class="token operator">===</span> <span class="token string">'dropzone'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment">// 恢复目标节点背景色</span>
    event<span class="token punctuation">.</span>target<span class="token punctuation">.</span>style<span class="token punctuation">.</span>background <span class="token operator">=</span> <span class="token string">''</span><span class="token punctuation">;</span>
    <span class="token comment">// 将被拖拉节点插入目标节点</span>
    dragged<span class="token punctuation">.</span>parentNode<span class="token punctuation">.</span><span class="token function">removeChild</span><span class="token punctuation">(</span>dragged<span class="token punctuation">)</span><span class="token punctuation">;</span>
    event<span class="token punctuation">.</span>target<span class="token punctuation">.</span><span class="token function">appendChild</span><span class="token punctuation">(</span> dragged <span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br><span class="line-number">31</span><br><span class="line-number">32</span><br><span class="line-number">33</span><br><span class="line-number">34</span><br><span class="line-number">35</span><br><span class="line-number">36</span><br><span class="line-number">37</span><br><span class="line-number">38</span><br><span class="line-number">39</span><br><span class="line-number">40</span><br><span class="line-number">41</span><br><span class="line-number">42</span><br><span class="line-number">43</span><br><span class="line-number">44</span><br><span class="line-number">45</span><br><span class="line-number">46</span><br><span class="line-number">47</span><br><span class="line-number">48</span><br><span class="line-number">49</span><br><span class="line-number">50</span><br><span class="line-number">51</span><br><span class="line-number">52</span><br><span class="line-number">53</span><br><span class="line-number">54</span><br><span class="line-number">55</span><br><span class="line-number">56</span><br><span class="line-number">57</span><br></div></div><p>关于拖拉事件，有以下几个注意点。</p> <ul><li>拖拉过程只触发以上这些拖拉事件，尽管鼠标在移动，但是<strong>鼠标事件不会触发</strong>。</li> <li>将文件从操作系统拖拉进浏览器，不会触发<code>dragstart</code>和<code>dragend</code>事件。</li> <li><code>dragenter</code>和<code>dragover</code>事件的监听函数，用来取出拖拉的数据（即允许放下被拖拉的元素）。由于网页的大部分区域不适合作为放下拖拉元素的目标节点，所以这两个事件的默认设置为当前节点不允许接受被拖拉的元素。<strong>如果想要在目标节点上放下的数据，首先必须阻止这两个事件的默认行为</strong>。</li></ul> <div class="language-html line-numbers-mode"><pre class="language-html"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">ondragover</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>return false<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">ondragover</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>event.preventDefault()<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br></div></div><p>上面代码中，如果不取消拖拉事件或者阻止默认行为，就不能在<code>div</code>节点上放下被拖拉的节点。</p> <h3 id="_2、dragevent-接口"><a href="#_2、dragevent-接口" class="header-anchor">#</a> 2、DragEvent 接口</h3> <p><strong>拖拉事件都继承了<code>DragEvent</code>接口，这个接口又继承了<code>MouseEvent</code>接口和<code>Event</code>接口。</strong></p> <p>浏览器原生提供一个<code>DragEvent()</code>构造函数，用来生成拖拉事件的实例对象。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token keyword">new</span> <span class="token class-name">DragEvent</span><span class="token punctuation">(</span>type<span class="token punctuation">,</span> options<span class="token punctuation">)</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><p><code>DragEvent()</code>构造函数接受两个参数，第一个参数是<strong>字符串，表示事件的类型</strong>，该参数必须；第二个参数是事件的<strong>配置对象</strong>，用来设置事件的属性，该参数可选。配置对象除了接受<code>MouseEvent</code>接口和<code>Event</code>接口的配置属性，还可以<strong>设置<code>dataTransfer</code>属性要么是<code>null</code>，要么是一个<code>DataTransfer</code>接口的实例。</strong></p> <p><code>DataTransfer</code>的实例对象用来读写拖拉事件中传输的数据，详见下文《DataTransfer 接口》的部分。</p> <h3 id="_3、datatransfer-接口概述"><a href="#_3、datatransfer-接口概述" class="header-anchor">#</a> 3、DataTransfer 接口概述</h3> <p><strong>所有拖拉事件的实例都有一个<code>DragEvent.dataTransfer</code>属性，用来读写需要传递的数据</strong>。这个属性的值是一个<code>DataTransfer</code>接口的实例。</p> <p>浏览器原生提供一个<code>DataTransfer()</code>构造函数，用来生成<code>DataTransfer</code>实例对象。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token keyword">var</span> dataTrans <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">DataTransfer</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><p><code>DataTransfer()</code>构造函数<strong>不接受参数</strong>。</p> <p>拖拉的数据分成两方面：<strong>数据的种类（又称格式）和数据的值</strong>。数据的种类是一个 MIME 字符串（比如<code>text/plain</code>、<code>image/jpeg</code>），数据的值是一个字符串。一般来说，如果拖拉一段文本，则数据默认就是那段文本；如果拖拉一个链接，则数据默认就是链接的 URL。</p> <p>拖拉事件开始时，开发者可以提供数据类型和数据值。拖拉过程中，开发者通过<code>dragenter</code>和<code>dragover</code>事件的监听函数，检查数据类型，以确定是否允许放下（drop）被拖拉的对象。比如，在只允许放下链接的区域，检查拖拉的数据类型是否为<code>text/uri-list</code>。</p> <p><strong>发生<code>drop</code>事件时，监听函数取出拖拉的数据，对其进行处理。</strong></p> <h3 id="_4、datatransfer-的实例属性"><a href="#_4、datatransfer-的实例属性" class="header-anchor">#</a> 4、DataTransfer 的实例属性</h3> <h4 id="_4-1-datatransfer-dropeffect-设置接受拖拉的区域的效果"><a href="#_4-1-datatransfer-dropeffect-设置接受拖拉的区域的效果" class="header-anchor">#</a> 4.1 DataTransfer.dropEffect 设置接受拖拉的区域的效果</h4> <p><code>DataTransfer.dropEffect</code>属性<strong>用来设置放下（drop）被拖拉节点时的效果</strong>，会影响到拖拉经过相关区域时鼠标的形状。它可能取下面的值。</p> <ul><li>copy：复制被拖拉的节点</li> <li>move：移动被拖拉的节点</li> <li>link：创建指向被拖拉的节点的链接</li> <li>none：无法放下被拖拉的节点</li></ul> <p>除了上面这些值，设置其他的值都是无效的。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code>target<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'dragover'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  e<span class="token punctuation">.</span><span class="token function">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  e<span class="token punctuation">.</span><span class="token function">stopPropagation</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  e<span class="token punctuation">.</span>dataTransfer<span class="token punctuation">.</span>dropEffect <span class="token operator">=</span> <span class="token string">'copy'</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br></div></div><p>上面代码中，被拖拉元素一旦<code>drop</code>，接受的区域会复制该节点。</p> <p><code>dropEffect</code>属性一般<strong>在<code>dragenter</code>和<code>dragover</code>事件的监听函数中设置</strong>，对于<code>dragstart</code>、<code>drag</code>、<code>dragleave</code>这三个事件，该属性不起作用。因为该属性只对接受被拖拉的节点的区域有效，对被拖拉的节点本身是无效的。进入目标区域后，拖拉行为会初始化成设定的效果。</p> <h4 id="_4-2-datatransfer-effectallowed-设置被拖拉的节点允许的效果"><a href="#_4-2-datatransfer-effectallowed-设置被拖拉的节点允许的效果" class="header-anchor">#</a> 4.2 DataTransfer.effectAllowed 设置被拖拉的节点允许的效果</h4> <p><code>DataTransfer.effectAllowed</code>属性<strong>设置本次拖拉中允许的效果</strong>。它可能取下面的值。</p> <ul><li>copy：复制被拖拉的节点</li> <li>move：移动被拖拉的节点</li> <li>link：创建指向被拖拉节点的链接</li> <li>copyLink：允许<code>copy</code>或<code>link</code></li> <li>copyMove：允许<code>copy</code>或<code>move</code></li> <li>linkMove：允许<code>link</code>或<code>move</code></li> <li>all：允许所有效果</li> <li>none：无法放下被拖拉的节点</li> <li>uninitialized：默认值，等同于<code>all</code></li></ul> <p>如果某种效果是不允许的，用户就无法在目标节点中达成这种效果。</p> <p><strong>这个属性与<code>dropEffect</code>属性是同一件事的两个方面。前者设置被拖拉的节点允许的效果，后者设置接受拖拉的区域的效果，它们往往配合使用。</strong></p> <p><strong><code>dragstart</code>事件的监听函数，可以用来设置这个属性</strong>。其他事件的监听函数里面设置这个属性是无效的。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code>source<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'dragstart'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// 被拖拉节点上设置</span>
  e<span class="token punctuation">.</span>dataTransfer<span class="token punctuation">.</span>effectAllowed <span class="token operator">=</span> <span class="token string">'move'</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

target<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'dragover'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// 接受区域节点上设置</span>
  e<span class="token punctuation">.</span>dataTransfer<span class="token punctuation">.</span>dropEffect <span class="token operator">=</span> <span class="token string">'move'</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br></div></div><p>只要<code>dropEffect</code>属性和<code>effectAllowed</code>属性之中，有一个为<code>none</code>，就无法在目标节点上完成<code>drop</code>操作。</p> <h4 id="_4-3-datatransfer-files-本地文件"><a href="#_4-3-datatransfer-files-本地文件" class="header-anchor">#</a> 4.3 DataTransfer.files 本地文件</h4> <p><code>DataTransfer.files</code>属性是<strong>一个 FileList 对象，包含一组本地文件</strong>，可以用来在拖拉操作中传送。如果本次拖拉不涉及文件，则该属性为空的 FileList 对象。</p> <h5 id="例子-接收拖拉文件"><a href="#例子-接收拖拉文件" class="header-anchor">#</a> 例子：接收拖拉文件</h5> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token comment">// HTML 代码如下</span>
<span class="token comment">// &lt;div id=&quot;output&quot; style=&quot;min-height: 200px;border: 1px solid black;&quot;&gt;</span>
<span class="token comment">//   文件拖拉到这里</span>
<span class="token comment">// &lt;/div&gt;</span>

<span class="token keyword">var</span> div <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'output'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

div<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">&quot;dragenter&quot;</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span> <span class="token parameter">event</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span>
  div<span class="token punctuation">.</span>textContent <span class="token operator">=</span> <span class="token string">''</span><span class="token punctuation">;</span>
  event<span class="token punctuation">.</span><span class="token function">stopPropagation</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  event<span class="token punctuation">.</span><span class="token function">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

div<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">&quot;dragover&quot;</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span> <span class="token parameter">event</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span>
  event<span class="token punctuation">.</span><span class="token function">stopPropagation</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  event<span class="token punctuation">.</span><span class="token function">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

div<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">&quot;drop&quot;</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span> <span class="token parameter">event</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span>
  event<span class="token punctuation">.</span><span class="token function">stopPropagation</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  event<span class="token punctuation">.</span><span class="token function">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">var</span> files <span class="token operator">=</span> event<span class="token punctuation">.</span>dataTransfer<span class="token punctuation">.</span>files<span class="token punctuation">;</span>
  <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">var</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> files<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    div<span class="token punctuation">.</span>textContent <span class="token operator">+=</span> files<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span>name <span class="token operator">+</span> <span class="token string">' '</span> <span class="token operator">+</span> files<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span>size <span class="token operator">+</span> <span class="token string">'字节\n'</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br></div></div><p>上面代码中，通过<code>dataTransfer.files</code>属性读取被拖拉的文件的信息。如果想要<strong>读取文件内容，就要使用<code>FileReader</code>对象。</strong></p> <div class="language-js line-numbers-mode"><pre class="language-js"><code>div<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'drop'</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  e<span class="token punctuation">.</span><span class="token function">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  e<span class="token punctuation">.</span><span class="token function">stopPropagation</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">var</span> fileList <span class="token operator">=</span> e<span class="token punctuation">.</span>dataTransfer<span class="token punctuation">.</span>files<span class="token punctuation">;</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>fileList<span class="token punctuation">.</span>length <span class="token operator">&gt;</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">var</span> file <span class="token operator">=</span> fileList<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
    <span class="token keyword">var</span> reader <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">FileReader</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    reader<span class="token punctuation">.</span><span class="token function">readAsDataURL</span><span class="token punctuation">(</span>file<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">// 解析为url</span>
    reader<span class="token punctuation">.</span><span class="token function-variable function">onloadend</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span>e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>readyState <span class="token operator">===</span> FileReader<span class="token punctuation">.</span><span class="token constant">DONE</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">var</span> content <span class="token operator">=</span> reader<span class="token punctuation">.</span>result<span class="token punctuation">;</span>
        div<span class="token punctuation">.</span>innerHTML <span class="token operator">=</span> <span class="token string">'&lt;img src=&quot;'</span><span class="token operator">+</span> content <span class="token operator">+</span><span class="token string">'&quot;&gt; File: '</span> <span class="token operator">+</span> file<span class="token punctuation">.</span>name <span class="token operator">+</span> <span class="token string">'\n\n'</span> <span class="token operator">+</span> content<span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
    reader<span class="token punctuation">.</span><span class="token function">readAsBinaryString</span><span class="token punctuation">(</span>file<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br></div></div><h4 id="_4-4-datatransfer-types-数据格式"><a href="#_4-4-datatransfer-types-数据格式" class="header-anchor">#</a> 4.4 DataTransfer.types 数据格式</h4> <p><code>DataTransfer.types</code>属性<strong>是一个只读的数组</strong>，每个成员是一个字符串，里面是<strong>拖拉的数据格式</strong>（通常是 MIME 值）。比如，如果拖拉的是文字，对应的成员就是<code>text/plain</code>。</p> <p>下面是一个例子，通过检查<code>dataTransfer</code>属性的类型，决定是否允许在当前节点执行<code>drop</code>操作。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token keyword">function</span> <span class="token function">contains</span><span class="token punctuation">(</span><span class="token parameter">list<span class="token punctuation">,</span> value</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
  <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">var</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> list<span class="token punctuation">.</span>length<span class="token punctuation">;</span> <span class="token operator">++</span>i<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span><span class="token punctuation">(</span>list<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">===</span> value<span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
  <span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">function</span> <span class="token function">doDragOver</span><span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">var</span> isLink <span class="token operator">=</span> <span class="token function">contains</span><span class="token punctuation">(</span>event<span class="token punctuation">.</span>dataTransfer<span class="token punctuation">.</span>types<span class="token punctuation">,</span> <span class="token string">'text/uri-list'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>isLink<span class="token punctuation">)</span> event<span class="token punctuation">.</span><span class="token function">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br></div></div><p>上面代码中，只有当被拖拉的节点是一个链接时，才允许在当前节点放下。</p> <h4 id="_4-5-datatransfer-items"><a href="#_4-5-datatransfer-items" class="header-anchor">#</a> 4.5 DataTransfer.items</h4> <p><code>DataTransfer.items</code>属性<strong>返回一个类似数组的只读对象（DataTransferItemList 实例）</strong>，每个成员就是本次拖拉的一个对象（DataTransferItem 实例）。如果本次拖拉不包含对象，则返回一个空对象。</p> <p>DataTransferItemList 实例具有以下的属性和方法。</p> <ul><li><code>length</code>：返回成员的数量</li> <li><code>add(data, type)</code>：增加一个指定内容和类型（比如<code>text/html</code>和<code>text/plain</code>）的字符串作为成员</li> <li><code>add(file)</code>：<code>add</code>方法的另一种用法，增加一个文件作为成员</li> <li><code>remove(index)</code>：移除指定位置的成员</li> <li><code>clear()</code>：移除所有的成员</li></ul> <p>DataTransferItem 实例具有以下的属性和方法。</p> <ul><li><code>kind</code>：返回成员的种类（<code>string</code>还是<code>file</code>）。</li> <li><code>type</code>：返回成员的类型（通常是 MIME 值）。</li> <li><code>getAsFile()</code>：如果被拖拉是文件，返回该文件，否则返回<code>null</code>。</li> <li><code>getAsString(callback)</code>：如果被拖拉的是字符串，将该字符传入指定的回调函数处理。该方法是异步的，所以需要传入回调函数。</li></ul> <p>下面是一个例子。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code>div<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'drop'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  e<span class="token punctuation">.</span><span class="token function">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>e<span class="token punctuation">.</span>dataTransfer<span class="token punctuation">.</span>items <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">var</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> e<span class="token punctuation">.</span>dataTransfer<span class="token punctuation">.</span>items<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>dataTransfer<span class="token punctuation">.</span>items<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span>kind <span class="token operator">+</span> <span class="token string">': '</span> <span class="token operator">+</span> e<span class="token punctuation">.</span>dataTransfer<span class="token punctuation">.</span>items<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span>type<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br></div></div><h3 id="_5、datatransfer-的实例方法"><a href="#_5、datatransfer-的实例方法" class="header-anchor">#</a> 5、DataTransfer 的实例方法</h3> <h4 id="_5-1-datatransfer-setdata-设置拖拉事件所带有的数据"><a href="#_5-1-datatransfer-setdata-设置拖拉事件所带有的数据" class="header-anchor">#</a> 5.1 DataTransfer.setData() 设置拖拉事件所带有的数据</h4> <p><code>DataTransfer.setData()</code>方法用来<strong>设置拖拉事件所带有的数据</strong>。该方法没有返回值。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code>event<span class="token punctuation">.</span>dataTransfer<span class="token punctuation">.</span><span class="token function">setData</span><span class="token punctuation">(</span><span class="token string">'text/plain'</span><span class="token punctuation">,</span> <span class="token string">'Text to drag'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><p>上面代码为当前的拖拉事件加入纯文本数据。</p> <p>该方法接受两个参数，都是字符串。第一个参数<strong>表示数据类型</strong>（比如<code>text/plain</code>），第二个参数是<strong>具体数据</strong>。如果指定类型的数据在<code>dataTransfer</code>属性不存在，那么这些数据将被加入，否则原有的数据将被新数据替换。</p> <p>如果是拖拉文本框或者拖拉选中的文本，会默认将对应的文本数据，添加到<code>dataTransfer</code>属性，不用手动指定。</p> <div class="language-html line-numbers-mode"><pre class="language-html"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">draggable</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>true<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
  aaa
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br></div></div><p>上面代码中，拖拉这个<code>&lt;div&gt;</code>元素会自动带上文本数据<code>aaa</code>。</p> <p>使用<code>setData</code>方法，可以替换到原有数据。</p> <div class="language-html line-numbers-mode"><pre class="language-html"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span>
  <span class="token attr-name">draggable</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>true<span class="token punctuation">&quot;</span></span>
  <span class="token attr-name">ondragstart</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>event.dataTransfer.setData(<span class="token punctuation">'</span>text/plain<span class="token punctuation">'</span>, <span class="token punctuation">'</span>bbb<span class="token punctuation">'</span>)<span class="token punctuation">&quot;</span></span>
<span class="token punctuation">&gt;</span></span>
  aaa
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br></div></div><p>上面代码中，拖拉数据实际上是<code>bbb</code>，而不是<code>aaa</code>。</p> <p>下面是添加其他类型的数据。由于<code>text/plain</code>是最普遍支持的格式，为了保证兼容性，建议最后总是保存一份纯文本格式的数据。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token keyword">var</span> dt <span class="token operator">=</span> event<span class="token punctuation">.</span>dataTransfer<span class="token punctuation">;</span>

<span class="token comment">// 添加链接</span>
dt<span class="token punctuation">.</span><span class="token function">setData</span><span class="token punctuation">(</span><span class="token string">'text/uri-list'</span><span class="token punctuation">,</span> <span class="token string">'http://www.example.com'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
dt<span class="token punctuation">.</span><span class="token function">setData</span><span class="token punctuation">(</span><span class="token string">'text/plain'</span><span class="token punctuation">,</span> <span class="token string">'http://www.example.com'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// 添加 HTML 代码</span>
dt<span class="token punctuation">.</span><span class="token function">setData</span><span class="token punctuation">(</span><span class="token string">'text/html'</span><span class="token punctuation">,</span> <span class="token string">'Hello there, &lt;strong&gt;stranger&lt;/strong&gt;'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
dt<span class="token punctuation">.</span><span class="token function">setData</span><span class="token punctuation">(</span><span class="token string">'text/plain'</span><span class="token punctuation">,</span> <span class="token string">'Hello there, &lt;strong&gt;stranger&lt;/strong&gt;'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// 添加图像的 URL</span>
dt<span class="token punctuation">.</span><span class="token function">setData</span><span class="token punctuation">(</span><span class="token string">'text/uri-list'</span><span class="token punctuation">,</span> imageurl<span class="token punctuation">)</span><span class="token punctuation">;</span>
dt<span class="token punctuation">.</span><span class="token function">setData</span><span class="token punctuation">(</span><span class="token string">'text/plain'</span><span class="token punctuation">,</span> imageurl<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br></div></div><p>可以一次提供多种格式的数据。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token keyword">var</span> dt <span class="token operator">=</span> event<span class="token punctuation">.</span>dataTransfer<span class="token punctuation">;</span>
dt<span class="token punctuation">.</span><span class="token function">setData</span><span class="token punctuation">(</span><span class="token string">'application/x-bookmark'</span><span class="token punctuation">,</span> bookmarkString<span class="token punctuation">)</span><span class="token punctuation">;</span>
dt<span class="token punctuation">.</span><span class="token function">setData</span><span class="token punctuation">(</span><span class="token string">'text/uri-list'</span><span class="token punctuation">,</span> <span class="token string">'http://www.example.com'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
dt<span class="token punctuation">.</span><span class="token function">setData</span><span class="token punctuation">(</span><span class="token string">'text/plain'</span><span class="token punctuation">,</span> <span class="token string">'http://www.example.com'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br></div></div><p>上面代码中，通过在同一个事件上面，存放三种类型的数据，使得拖拉事件可以在不同的对象上面，<code>drop</code>不同的值。注意，第一种格式是一个自定义格式，浏览器默认无法读取，这意味着，只有某个部署了特定代码的节点，才可能<code>drop</code>（读取到）这个数据。</p> <h4 id="_5-2-datatransfer-getdata-返回指定类型的数据"><a href="#_5-2-datatransfer-getdata-返回指定类型的数据" class="header-anchor">#</a> 5.2 DataTransfer.getData() 返回指定类型的数据</h4> <p><code>DataTransfer.getData()</code>方法接受一个字符串（表示数据类型）作为参数，<strong>返回事件所带的指定类型的数据（通常是用<code>setData</code>方法添加的数据）</strong>。如果指定类型的数据不存在，则返回空字符串。通常只有<code>drop</code>事件触发后，才能取出数据。</p> <p>下面是一个<code>drop</code>事件的监听函数，用来取出指定类型的数据。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token keyword">function</span> <span class="token function">onDrop</span><span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">var</span> data <span class="token operator">=</span> event<span class="token punctuation">.</span>dataTransfer<span class="token punctuation">.</span><span class="token function">getData</span><span class="token punctuation">(</span><span class="token string">'text/plain'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  event<span class="token punctuation">.</span>target<span class="token punctuation">.</span>textContent <span class="token operator">=</span> data<span class="token punctuation">;</span>
  event<span class="token punctuation">.</span><span class="token function">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br></div></div><p>上面代码取出拖拉事件的文本数据，将其替换成当前节点的文本内容。注意，这时还必须取消浏览器的默认行为，因为假如用户拖拉的是一个链接，浏览器默认会在当前窗口打开这个链接。</p> <p><code>getData</code>方法返回的是一个字符串，如果其中包含多项数据，就必须手动解析。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token keyword">function</span> <span class="token function">doDrop</span><span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">var</span> lines <span class="token operator">=</span> event<span class="token punctuation">.</span>dataTransfer<span class="token punctuation">.</span><span class="token function">getData</span><span class="token punctuation">(</span><span class="token string">'text/uri-list'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token string">'\n'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> line <span class="token keyword">of</span> lines<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">let</span> link <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">'a'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    link<span class="token punctuation">.</span>href <span class="token operator">=</span> line<span class="token punctuation">;</span>
    link<span class="token punctuation">.</span>textContent <span class="token operator">=</span> line<span class="token punctuation">;</span>
    event<span class="token punctuation">.</span>target<span class="token punctuation">.</span><span class="token function">appendChild</span><span class="token punctuation">(</span>link<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
  event<span class="token punctuation">.</span><span class="token function">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br></div></div><p>上面代码中，<code>getData</code>方法返回的是一组链接，就必须自行解析。</p> <p>类型值指定为<code>URL</code>，可以取出第一个有效链接。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token keyword">var</span> link <span class="token operator">=</span> event<span class="token punctuation">.</span>dataTransfer<span class="token punctuation">.</span><span class="token function">getData</span><span class="token punctuation">(</span><span class="token string">'URL'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><p>下面的例子是从多种类型的数据里面取出数据。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token keyword">function</span> <span class="token function">doDrop</span><span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">var</span> types <span class="token operator">=</span> event<span class="token punctuation">.</span>dataTransfer<span class="token punctuation">.</span>types<span class="token punctuation">;</span>
  <span class="token keyword">var</span> supportedTypes <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">'text/uri-list'</span><span class="token punctuation">,</span> <span class="token string">'text/plain'</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
  types <span class="token operator">=</span> supportedTypes<span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">value</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> types<span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span>value<span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>types<span class="token punctuation">.</span>length<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">var</span> data <span class="token operator">=</span> event<span class="token punctuation">.</span>dataTransfer<span class="token punctuation">.</span><span class="token function">getData</span><span class="token punctuation">(</span>types<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
  event<span class="token punctuation">.</span><span class="token function">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br></div></div><h4 id="_5-3-datatransfer-cleardata-清除指定或全部数据"><a href="#_5-3-datatransfer-cleardata-清除指定或全部数据" class="header-anchor">#</a> 5.3 DataTransfer.clearData() 清除指定或全部数据</h4> <p><code>DataTransfer.clearData()</code>方法接受一个字符串（表示数据类型）作为参数，删除事件所带的指定类型的数据。如果没有指定类型，则删除所有数据。如果指定类型不存在，则调用该方法不会产生任何效果。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code>event<span class="token punctuation">.</span>dataTransfer<span class="token punctuation">.</span><span class="token function">clearData</span><span class="token punctuation">(</span><span class="token string">'text/uri-list'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><p>上面代码清除事件所带的<code>text/uri-list</code>类型的数据。</p> <p>该方法不会移除拖拉的文件，因此调用该方法后，<code>DataTransfer.types</code>属性可能依然会返回<code>Files</code>类型（前提是存在文件拖拉）。</p> <p>注意，该方法<strong>只能在<code>dragstart</code>事件的监听函数之中使用</strong>，因为这是拖拉操作的数据唯一可写的时机。</p> <h4 id="_5-4-datatransfer-setdragimage-设置拖动过程中的图片"><a href="#_5-4-datatransfer-setdragimage-设置拖动过程中的图片" class="header-anchor">#</a> 5.4 DataTransfer.setDragImage() 设置拖动过程中的图片</h4> <p>拖动过程中（<code>dragstart</code>事件触发后），浏览器<strong>会显示一张图片跟随鼠标一起移动</strong>，表示被拖动的节点。这张图片是<strong>自动创造的</strong>，通常显示为被拖动节点的外观，不需要自己动手设置。</p> <p><code>DataTransfer.setDragImage()</code>方法<strong>可以自定义这张图片</strong>。它接受三个参数。第一个是<code>&lt;img&gt;</code>节点或者<code>&lt;canvas&gt;</code>节点，如果省略或为<code>null</code>，则使用被拖动的节点的外观；第二个和第三个参数为鼠标相对于该图片左上角的横坐标和右坐标。</p> <p>下面是一个例子。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token comment">/* HTML 代码如下
 &lt;div id=&quot;drag-with-image&quot; class=&quot;dragdemo&quot; draggable=&quot;true&quot;&gt;
   drag me
 &lt;/div&gt;
*/</span>

<span class="token keyword">var</span> div <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'drag-with-image'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
div<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'dragstart'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">var</span> img <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">'img'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  img<span class="token punctuation">.</span>src <span class="token operator">=</span> <span class="token string">'http://path/to/img'</span><span class="token punctuation">;</span>
  e<span class="token punctuation">.</span>dataTransfer<span class="token punctuation">.</span><span class="token function">setDragImage</span><span class="token punctuation">(</span>img<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br></div></div><h2 id="十、其他常见事件"><a href="#十、其他常见事件" class="header-anchor">#</a> 十、其他常见事件</h2> <h3 id="_1、资源事件"><a href="#_1、资源事件" class="header-anchor">#</a> 1、资源事件</h3> <h4 id="_1-1-beforeunload-事件-关闭窗口前调用"><a href="#_1-1-beforeunload-事件-关闭窗口前调用" class="header-anchor">#</a> 1.1 beforeunload 事件 （关闭窗口前调用）</h4> <p><code>beforeunload</code>事件在<strong>窗口、文档、各种资源将要卸载前触发</strong>。它可以用来防止用户不小心卸载资源。</p> <p>如果该事件对象的<code>returnValue</code>属性是一个非空字符串，那么浏览器就会弹出一个对话框，询问用户是否要卸载该资源。但是，用户指定的字符串可能无法显示，浏览器会展示预定义的字符串。如果用户点击“取消”按钮，资源就不会卸载。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code>window<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'beforeunload'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  event<span class="token punctuation">.</span>returnValue <span class="token operator">=</span> <span class="token string">'你确定离开吗？'</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br></div></div><p>上面代码中，用户如果<strong>关闭窗口，浏览器会弹出一个窗口，要求用户确认</strong>。</p> <p>浏览器对这个事件的行为很不一致，有的浏览器调用<code>event.preventDefault()</code>，也会弹出对话框。IE 浏览器需要显式返回一个非空的字符串，才会弹出对话框。而且，<strong>大多数浏览器在对话框中不显示指定文本，只显示默认文本</strong>。因此，可以采用下面的写法，取得最大的兼容性。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code>window<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'beforeunload'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">var</span> confirmationMessage <span class="token operator">=</span> <span class="token string">'确认关闭窗口？'</span><span class="token punctuation">;</span>

  e<span class="token punctuation">.</span>returnValue <span class="token operator">=</span> confirmationMessage<span class="token punctuation">;</span>
  <span class="token keyword">return</span> confirmationMessage<span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br></div></div><p>注意，许多手机浏览器默认忽略这个事件，桌面浏览器也有办法忽略这个事件。所以，它可能根本不会生效，不能依赖它来阻止用户关闭窗口。另外，一旦使用了<code>beforeunload</code>事件，浏览器就不会缓存当前网页，使用“回退”按钮将重新向服务器请求网页。这是因为监听这个事件的目的，一般是修改初始状态，这时缓存初始页面就没意义了。</p> <p>基本上，只有一种场合可以监听<code>unload</code>事件，其他情况都不应该监听：<strong>用户修改了表单，还没有保存就要离开</strong>。</p> <h4 id="_1-2-unload-事件-即将关闭窗口时调用"><a href="#_1-2-unload-事件-即将关闭窗口时调用" class="header-anchor">#</a> 1.2 unload 事件 （即将关闭窗口时调用）</h4> <p><code>unload</code>事件在<strong>窗口关闭或者<code>document</code>对象将要卸载时触发</strong>。它的触发顺序排在<code>beforeunload</code>、<code>pagehide</code>事件后面。</p> <p><code>unload</code>事件发生时，文档处于一个特殊状态。所有资源依然存在，但是对用户来说都不可见，UI 互动全部无效。这个事件是无法取消的，即使在监听函数里面抛出错误，也不能停止文档的卸载。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code>window<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'unload'</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'文档将要卸载'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br></div></div><p>手机上，浏览器或系统可能会直接丢弃网页，这时该事件根本不会发生。而且跟<code>beforeunload</code>事件一样，一旦使用了<code>unload</code>事件，浏览器就不会缓存当前网页，理由同上。因此，任何情况下都不应该依赖这个事件，指定网页卸载时要执行的代码，可以考虑完全不使用这个事件。</p> <h4 id="_1-3-load-事件-error-事件-abort事件-页面或某个资源加载成功-失败-取消时调用"><a href="#_1-3-load-事件-error-事件-abort事件-页面或某个资源加载成功-失败-取消时调用" class="header-anchor">#</a> 1.3 load 事件，error 事件 ，abort事件 （页面或某个资源加载成功/失败/取消时调用）</h4> <p><code>load</code>事件<strong>在页面或某个资源加载成功时触发</strong>。注意，<strong>页面或资源从浏览器缓存加载，并不会触发<code>load</code>事件</strong>。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code>window<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'load'</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'所有资源都加载完成'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br></div></div><p><code>error</code>事件是<strong>在页面或资源加载失败时触发</strong>。</p> <p><code>abort</code>事件是<strong>在用户取消加载时触发</strong>。</p> <p>这三个事件实际上属于进度事件，不仅发生在<code>document</code>对象，还发生在各种外部资源上面。浏览网页就是一个加载各种资源的过程，图像（image）、样式表（style sheet）、脚本（script）、视频（video）、音频（audio）、Ajax请求（XMLHttpRequest）等等。这些资源和<code>document</code>对象、<code>window</code>对象、XMLHttpRequestUpload 对象，都会触发<code>load</code>事件和<code>error</code>事件。</p> <p><strong>触发这三个事件的对象有</strong>：</p> <ul><li>window</li> <li>document</li> <li>body</li> <li>img</li> <li>style</li> <li>script</li> <li>video</li> <li>audio</li> <li>Ajax</li> <li>等等</li></ul> <h3 id="_2、session-历史事件"><a href="#_2、session-历史事件" class="header-anchor">#</a> 2、session 历史事件</h3> <h4 id="_2-1-pageshow-事件-页面显示-加载页面后执行-pagehide-事件-退出当前页面触发"><a href="#_2-1-pageshow-事件-页面显示-加载页面后执行-pagehide-事件-退出当前页面触发" class="header-anchor">#</a> 2.1 pageshow 事件（页面显示，加载页面后执行），pagehide 事件（退出当前页面触发）</h4> <p>默认情况下，浏览器会在当前会话（session）缓存页面，当用户<strong>点击“前进/后退”按钮时，浏览器就会从缓存中加载页面。</strong></p> <p>pageshow 事件<strong>在页面加载时触发，包括第一次加载和从缓存加载两种情况</strong>。如果要指定页面每次加载（不管是不是从浏览器缓存）时都运行的代码，可以放在这个事件的监听函数。</p> <p>第一次加载时，它的触发顺序排在<code>load</code>事件后面。从缓存加载时，<code>load</code>事件不会触发，因为网页在缓存中的样子通常是<code>load</code>事件的监听函数运行后的样子，所以不必重复执行。同理，如果是从缓存中加载页面，网页内初始化的 JavaScript 脚本（比如 DOMContentLoaded 事件的监听函数）也不会执行。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code>window<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'pageshow'</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'pageshow: '</span><span class="token punctuation">,</span> event<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br></div></div><p>pageshow 事件<strong>有一个<code>persisted</code>属性</strong>，返回一个布尔值。页面第一次加载时，这个属性是<code>false</code>；当页面从缓存加载时，这个属性是<code>true</code>。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code>window<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'pageshow'</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>event<span class="token punctuation">.</span>persisted<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// 是否从缓存加载</span>
    <span class="token comment">// ...</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br></div></div><p><code>pagehide</code>事件与<code>pageshow</code>事件类似，当用户<strong>通过“前进/后退”按钮，离开当前页面时触发</strong>。它与 unload 事件的区别在于，如果在 window 对象上定义<code>unload</code>事件的监听函数之后，页面不会保存在缓存中，而使用<code>pagehide</code>事件，页面会保存在缓存中。</p> <p><code>pagehide</code>事件实例也<strong>有一个<code>persisted</code>属性，将这个属性设为<code>true</code>，就表示页面要保存在缓存中；设为<code>false</code>，表示网页不保存在缓存中</strong>，这时如果设置了unload 事件的监听函数，该函数将在 pagehide 事件后立即运行。</p> <p>如果页面包含<code>&lt;frame&gt;</code>或<code>&lt;iframe&gt;</code>元素，则<code>&lt;frame&gt;</code>页面的<code>pageshow</code>事件和<code>pagehide</code>事件，都会在主页面之前触发。</p> <p><strong>注意，这两个事件只在浏览器的<code>history</code>（历史）对象发生变化时触发，跟网页是否可见没有关系。</strong></p> <h4 id="_2-2-popstate-事件-在浏览器的history对象的当前记录发生显式切换时触发"><a href="#_2-2-popstate-事件-在浏览器的history对象的当前记录发生显式切换时触发" class="header-anchor">#</a> 2.2 popstate 事件（在浏览器的<code>history</code>对象的当前记录发生显式切换时触发）</h4> <p><code>popstate</code>事件<strong>在浏览器的<code>history</code>对象的当前记录发生显式切换时触发</strong>。注意，调用<code>history.pushState()</code>或<code>history.replaceState()</code>，并不会触发<code>popstate</code>事件。该事件只在用户在<code>history</code>记录之间显式切换时触发，比如<strong>鼠标点击“后退/前进”按钮，或者在脚本中调用<code>history.back()</code>、<code>history.forward()</code>、<code>history.go()</code>时触发</strong>。</p> <p>该事件对象有一个<code>state</code>属性，保存<code>history.pushState</code>方法和<code>history.replaceState</code>方法为当前记录添加的<code>state</code>对象。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code>window<span class="token punctuation">.</span><span class="token function-variable function">onpopstate</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'state: '</span> <span class="token operator">+</span> event<span class="token punctuation">.</span>state<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
history<span class="token punctuation">.</span><span class="token function">pushState</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token literal-property property">page</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token string">'title 1'</span><span class="token punctuation">,</span> <span class="token string">'?page=1'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
history<span class="token punctuation">.</span><span class="token function">pushState</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token literal-property property">page</span><span class="token operator">:</span> <span class="token number">2</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token string">'title 2'</span><span class="token punctuation">,</span> <span class="token string">'?page=2'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
history<span class="token punctuation">.</span><span class="token function">replaceState</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token literal-property property">page</span><span class="token operator">:</span> <span class="token number">3</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token string">'title 3'</span><span class="token punctuation">,</span> <span class="token string">'?page=3'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
history<span class="token punctuation">.</span><span class="token function">back</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// state: {&quot;page&quot;:1}</span>
history<span class="token punctuation">.</span><span class="token function">back</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// state: null</span>
history<span class="token punctuation">.</span><span class="token function">go</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span>  <span class="token comment">// state: {&quot;page&quot;:3}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br></div></div><p>上面代码中，<code>pushState</code>方法向<code>history</code>添加了两条记录，然后<code>replaceState</code>方法替换掉当前记录。因此，连续两次<code>back</code>方法，会让当前条目退回到原始网址，它没有附带<code>state</code>对象，所以事件的<code>state</code>属性为<code>null</code>，然后前进两条记录，又回到<code>replaceState</code>方法添加的记录。</p> <p>浏览器对于页面首次加载，是否触发<code>popstate</code>事件，处理不一样，Firefox 不触发该事件。</p> <h4 id="_2-3-hashchange-事件-hash发生变化时触发"><a href="#_2-3-hashchange-事件-hash发生变化时触发" class="header-anchor">#</a> 2.3 hashchange 事件 （hash发生变化时触发）</h4> <p><code>hashchange</code>事件在 U<strong>RL 的 hash 部分（即<code>#</code>号后面的部分，包括<code>#</code>号）发生变化时触发</strong>。该事件<strong>一般在<code>window</code>对象上监听</strong>。</p> <p><code>hashchange</code>的事件实例具有两个特有属性：<code>oldURL</code>属性和<code>newURL</code>属性，分别表示变化前后的完整 URL。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token comment">// URL 是 http://www.example.com/</span>
window<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'hashchange'</span><span class="token punctuation">,</span> myFunction<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">function</span> <span class="token function">myFunction</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>oldURL<span class="token punctuation">)</span><span class="token punctuation">;</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>newURL<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

location<span class="token punctuation">.</span>hash <span class="token operator">=</span> <span class="token string">'part2'</span><span class="token punctuation">;</span>
<span class="token comment">// http://www.example.com/</span>
<span class="token comment">// http://www.example.com/#part2</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br></div></div><h3 id="_3、网页状态事件"><a href="#_3、网页状态事件" class="header-anchor">#</a> 3、网页状态事件</h3> <h4 id="_3-1-domcontentloaded-事件-dom内容加载完成后触发"><a href="#_3-1-domcontentloaded-事件-dom内容加载完成后触发" class="header-anchor">#</a> 3.1 DOMContentLoaded 事件 （DOM内容加载完成后触发）</h4> <p><strong>网页下载并解析完成以后，浏览器就会在<code>document</code>对象上触发 DOMContentLoaded 事件</strong>。这时，仅仅完成了网页的解析（整张页面的 DOM 生成了），<strong>所有外部资源（样式表、脚本、iframe 等等）可能还没有下载结束</strong>。也就是说，这个事件<strong>比<code>load</code>事件，发生时间早得多</strong>。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code>document<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'DOMContentLoaded'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'DOM生成'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br></div></div><p>注意，网页的 JavaScript 脚本是同步执行的，脚本一旦发生堵塞，将推迟触发<code>DOMContentLoaded</code>事件。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code>document<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'DOMContentLoaded'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'DOM 生成'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// 这段代码会推迟触发 DOMContentLoaded 事件</span>
<span class="token keyword">for</span><span class="token punctuation">(</span><span class="token keyword">var</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> <span class="token number">1000000000</span><span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment">// ...</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br></div></div><h4 id="_3-2-readystatechange-事件-document-对象和-xmlhttprequest-对象的readystate属性发生变化时触发"><a href="#_3-2-readystatechange-事件-document-对象和-xmlhttprequest-对象的readystate属性发生变化时触发" class="header-anchor">#</a> 3.2 readystatechange 事件（Document 对象和 XMLHttpRequest 对象的<code>readyState</code>属性发生变化时触发）</h4> <p><code>readystatechange</code>事件<strong>当 Document 对象和 XMLHttpRequest 对象的<code>readyState</code>属性发生变化时触发</strong>。<code>document.readyState</code>有三个可能的值：<code>loading</code>（网页正在加载）、<code>interactive</code>（网页已经解析完成，但是外部资源仍然处在加载状态）和<code>complete</code>（网页和所有外部资源已经结束加载，<code>load</code>事件即将触发）。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code>document<span class="token punctuation">.</span><span class="token function-variable function">onreadystatechange</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>document<span class="token punctuation">.</span>readyState <span class="token operator">===</span> <span class="token string">'interactive'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment">// ...</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br></div></div><p>这个事件可以看作<code>DOMContentLoaded</code>事件的另一种实现方法。</p> <h3 id="_4、窗口事件"><a href="#_4、窗口事件" class="header-anchor">#</a> 4、窗口事件</h3> <h4 id="_4-1-scroll-事件-文档或文档元素滚动时触发"><a href="#_4-1-scroll-事件-文档或文档元素滚动时触发" class="header-anchor">#</a> 4.1 scroll 事件 （文档或文档元素滚动时触发）</h4> <p><code>scroll</code>事件在<strong>文档或文档元素滚动时触发</strong>，主要出现在用户拖动滚动条。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code>window<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'scroll'</span><span class="token punctuation">,</span> callback<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><p>该事件<strong>会连续地大量触发</strong>，所以它的监听函数之中不应该有非常耗费计算的操作。推荐的做法是使用<code>requestAnimationFrame</code>或<code>setTimeout</code>控制该事件的触发频率，然后可以结合<code>customEvent</code>抛出一个新事件。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">var</span> <span class="token function-variable function">throttle</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">type<span class="token punctuation">,</span> name<span class="token punctuation">,</span> obj</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// 节流函数 控制触发频率</span>
    <span class="token keyword">var</span> obj <span class="token operator">=</span> obj <span class="token operator">||</span> window<span class="token punctuation">;</span>
    <span class="token keyword">var</span> running <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
    <span class="token keyword">var</span> <span class="token function-variable function">func</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span>running<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
      running <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
      <span class="token function">requestAnimationFrame</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// 结合此方法控制在每秒60次</span>
        obj<span class="token punctuation">.</span><span class="token function">dispatchEvent</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">CustomEvent</span><span class="token punctuation">(</span>name<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        running <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">;</span>
    obj<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span>type<span class="token punctuation">,</span> func<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">;</span>

  <span class="token comment">// 将 scroll 事件重定义为 optimizedScroll 事件</span>
  <span class="token function">throttle</span><span class="token punctuation">(</span><span class="token string">'scroll'</span><span class="token punctuation">,</span> <span class="token string">'optimizedScroll'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

window<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'optimizedScroll'</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Resource conscious scroll callback!'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br></div></div><p>上面代码中，<code>throttle</code>函数用于控制事件触发频率，<code>requestAnimationFrame</code>方法保证每次页面重绘（每秒60次），只会触发一次<code>scroll</code>事件的监听函数。也就是说，上面方法将<code>scroll</code>事件的触发频率，限制在每秒60次。具体来说，就是<code>scroll</code>事件只要频率低于每秒60次，就会触发<code>optimizedScroll</code>事件，从而执行<code>optimizedScroll</code>事件的监听函数。</p> <p>改用<code>setTimeout</code>方法，可以放置更大的时间间隔。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  window<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'scroll'</span><span class="token punctuation">,</span> scrollThrottler<span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">var</span> scrollTimeout<span class="token punctuation">;</span>
  <span class="token keyword">function</span> <span class="token function">scrollThrottler</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>scrollTimeout<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      scrollTimeout <span class="token operator">=</span> <span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        scrollTimeout <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
        <span class="token function">actualScrollHandler</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">66</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>

  <span class="token keyword">function</span> <span class="token function">actualScrollHandler</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment">// ...</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br></div></div><p>上面代码中，每次<code>scroll</code>事件都会执行<code>scrollThrottler</code>函数。该函数里面有一个定时器<code>setTimeout</code>，每66毫秒触发一次（每秒15次）真正执行的任务<code>actualScrollHandler</code>。</p> <p>下面是一个更一般的<code>throttle</code>函数的写法。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token keyword">function</span> <span class="token function">throttle</span><span class="token punctuation">(</span><span class="token parameter">fn<span class="token punctuation">,</span> wait</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">var</span> time <span class="token operator">=</span> Date<span class="token punctuation">.</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">return</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token punctuation">(</span>time <span class="token operator">+</span> wait <span class="token operator">-</span> Date<span class="token punctuation">.</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">&lt;</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token function">fn</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      time <span class="token operator">=</span> Date<span class="token punctuation">.</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

window<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'scroll'</span><span class="token punctuation">,</span> <span class="token function">throttle</span><span class="token punctuation">(</span>callback<span class="token punctuation">,</span> <span class="token number">1000</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br></div></div><p>上面的代码将<code>scroll</code>事件的触发频率，限制在一秒一次。</p> <p><a href="https://www.lodashjs.com/" target="_blank" rel="noopener noreferrer">lodash<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a>函数库提供了现成的<code>throttle</code>函数，可以直接使用。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code>window<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'scroll'</span><span class="token punctuation">,</span> _<span class="token punctuation">.</span><span class="token function">throttle</span><span class="token punctuation">(</span>callback<span class="token punctuation">,</span> <span class="token number">1000</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><p>本书前面介绍过<code>debounce</code>的概念，<code>throttle</code>与它区别在于，<code>throttle</code>是“节流”，确保一段时间内只执行一次，而<code>debounce</code>是“防抖”，要连续操作结束后再执行。以网页滚动为例，<code>debounce</code>要等到用户停止滚动后才执行，<code>throttle</code>则是如果用户一直在滚动网页，那么在滚动过程中还是会执行。</p> <h4 id="_4-2-resize-事件-窗口大小变化时触发"><a href="#_4-2-resize-事件-窗口大小变化时触发" class="header-anchor">#</a> 4.2 resize 事件（窗口大小变化时触发）</h4> <p><code>resize</code>事件<strong>在改变浏览器窗口大小时触发</strong>，主要<strong>发生在<code>window</code>对象上面</strong>。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token keyword">var</span> <span class="token function-variable function">resizeMethod</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>document<span class="token punctuation">.</span>body<span class="token punctuation">.</span>clientWidth <span class="token operator">&lt;</span> <span class="token number">768</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'移动设备的视口'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

window<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'resize'</span><span class="token punctuation">,</span> resizeMethod<span class="token punctuation">,</span> <span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br></div></div><p>该事件也会连续地大量触发，所以最好像上面的<code>scroll</code>事件一样，通过<code>throttle</code>函数控制事件触发频率。</p> <h4 id="_4-3-fullscreenchange-事件-元素进入-退出全屏时触发-fullscreenerror-事件-无法切换全屏时触发"><a href="#_4-3-fullscreenchange-事件-元素进入-退出全屏时触发-fullscreenerror-事件-无法切换全屏时触发" class="header-anchor">#</a> 4.3 fullscreenchange 事件（元素进入/退出全屏时触发），fullscreenerror 事件（无法切换全屏时触发）</h4> <p><code>fullscreenchange</code>事件<strong>在元素进入或退出全屏状态时触发</strong>，该事件<strong>发生在<code>document</code>对象上面</strong>。</p> <p><strong>注意，此事件非浏览器的进入/退出全屏时触发的事件。</strong></p> <div class="language-js line-numbers-mode"><pre class="language-js"><code>document<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'fullscreenchange'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>document<span class="token punctuation">.</span>fullscreenElement<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 全屏的元素，如果为null时表示已退出全屏</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
document<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'click'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'div'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">requestFullscreen</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 设置元素为全屏展示</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br></div></div><p><code>fullscreenerror</code>事件在<strong>浏览器无法切换到全屏状态时触发</strong>。</p> <h3 id="_5、剪贴板事件"><a href="#_5、剪贴板事件" class="header-anchor">#</a> 5、剪贴板事件</h3> <p>以下三个事件属于剪贴板操作的相关事件。</p> <ul><li><code>cut</code>：将选中的内容从文档中移除，加入剪贴板时触发。<strong>【剪切】</strong></li> <li><code>copy</code>：进行复制动作时触发。<strong>【拷贝】</strong></li> <li><code>paste</code>：剪贴板内容粘贴到文档后触发。<strong>【粘贴】</strong></li></ul> <p>这三个事件都是**<code>ClipboardEvent</code>接口的实例**。<code>ClipboardEvent</code>有一个实例属性<code>clipboardData</code>，是一个 DataTransfer 对象，存放剪贴的数据。具体的 API 接口和操作方法，请参见《拖拉事件》的 DataTransfer 对象部分。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code>document<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'copy'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  e<span class="token punctuation">.</span>clipboardData<span class="token punctuation">.</span><span class="token function">setData</span><span class="token punctuation">(</span><span class="token string">'text/plain'</span><span class="token punctuation">,</span> <span class="token string">'Hello, world!'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  e<span class="token punctuation">.</span>clipboardData<span class="token punctuation">.</span><span class="token function">setData</span><span class="token punctuation">(</span><span class="token string">'text/html'</span><span class="token punctuation">,</span> <span class="token string">'&lt;b&gt;Hello, world!&lt;/b&gt;'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  e<span class="token punctuation">.</span><span class="token function">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br></div></div><p>上面的代码使得复制进入剪贴板的，都是开发者指定的数据，而不是用户想要拷贝的数据。</p> <h3 id="_6、焦点事件"><a href="#_6、焦点事件" class="header-anchor">#</a> 6、焦点事件</h3> <p>焦点事件发生在元素节点和<code>document</code>对象上面，与获得或失去焦点相关。它主要包括以下四个事件。</p> <ul><li><code>focus</code>：元素节点<strong>获得焦点</strong>后触发，该事件不会冒泡。</li> <li><code>blur</code>：元素节点<strong>失去焦点</strong>后触发，该事件不会冒泡。</li> <li><code>focusin</code>：元素节点<strong>将要获得焦点</strong>时触发，发生在<code>focus</code>事件之前。该事件会冒泡。</li> <li><code>focusout</code>：元素节点<strong>将要失去焦点</strong>时触发，发生在<code>blur</code>事件之前。该事件会冒泡。</li></ul> <p>这四个事件都继承了<code>FocusEvent</code>接口。<code>FocusEvent</code>实例具有以下属性。</p> <ul><li><code>FocusEvent.target</code>：事件的目标节点。</li> <li><code>FocusEvent.relatedTarget</code>：对于<code>focusin</code>事件，返回失去焦点的节点；对于<code>focusout</code>事件，返回将要接受焦点的节点；对于<code>focus</code>和<code>blur</code>事件，返回<code>null</code>。</li></ul> <p>由于<code>focus</code>和<code>blur</code>事件不会冒泡，只能在捕获阶段触发，所以<code>addEventListener</code>方法的第三个参数需要设为<code>true</code>。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code>form<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'focus'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  event<span class="token punctuation">.</span>target<span class="token punctuation">.</span>style<span class="token punctuation">.</span>background <span class="token operator">=</span> <span class="token string">'pink'</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

form<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'blur'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  event<span class="token punctuation">.</span>target<span class="token punctuation">.</span>style<span class="token punctuation">.</span>background <span class="token operator">=</span> <span class="token string">''</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br></div></div><p>上面代码针对表单的文本输入框，接受焦点时设置背景色，失去焦点时去除背景色。</p> <h3 id="_7、customevent-接口-自定义事件"><a href="#_7、customevent-接口-自定义事件" class="header-anchor">#</a> 7、CustomEvent 接口（自定义事件）</h3> <p>CustomEvent 接口<strong>用于生成自定义的事件实例</strong>。那些浏览器预定义的事件，虽然可以手动生成，但是往往不能在事件上绑定数据。如果需要在触发事件的同时，传入指定的数据，就可以使用 CustomEvent 接口生成的自定义事件对象。</p> <p>浏览器原生提供<code>CustomEvent()</code>构造函数，用来生成 CustomEvent 事件实例。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token keyword">new</span> <span class="token class-name">CustomEvent</span><span class="token punctuation">(</span>type<span class="token punctuation">,</span> options<span class="token punctuation">)</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><p><code>CustomEvent()</code>构造函数接受两个参数。第一个参数是字符串，表示事件的名字，这是必须的。第二个参数是事件的配置对象，这个参数是可选的。<code>CustomEvent</code>的配置对象除了接受 Event 事件的配置属性，只有一个自己的属性。</p> <ul><li><code>detail</code>：表示事件的附带数据，默认为<code>null</code>。</li></ul> <p>下面是一个例子。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token keyword">var</span> event <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">CustomEvent</span><span class="token punctuation">(</span><span class="token string">'build'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token string-property property">'detail'</span><span class="token operator">:</span> <span class="token string">'hello'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">function</span> <span class="token function">eventHandler</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>detail<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

document<span class="token punctuation">.</span>body<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'build'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>detail<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

document<span class="token punctuation">.</span>body<span class="token punctuation">.</span><span class="token function">dispatchEvent</span><span class="token punctuation">(</span>event<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br></div></div><p>上面代码中，我们手动定义了<code>build</code>事件。该事件触发后，会被监听到，从而输出该事件实例的<code>detail</code>属性（即字符串<code>hello</code>）。</p> <p>下面是另一个例子。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token keyword">var</span> myEvent <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">CustomEvent</span><span class="token punctuation">(</span><span class="token string">'myevent'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
  <span class="token literal-property property">detail</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">foo</span><span class="token operator">:</span> <span class="token string">'bar'</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token literal-property property">bubbles</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
  <span class="token literal-property property">cancelable</span><span class="token operator">:</span> <span class="token boolean">false</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

el<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'myevent'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Hello '</span> <span class="token operator">+</span> event<span class="token punctuation">.</span>detail<span class="token punctuation">.</span>foo<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

el<span class="token punctuation">.</span><span class="token function">dispatchEvent</span><span class="token punctuation">(</span>myEvent<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br></div></div><p>上面代码也说明，CustomEvent 的事件实例，除了具有 Event 接口的实例属性，还具有<code>detail</code>属性。</p> <h2 id="十一、globaleventhandlers-接口-全局事件处理接口"><a href="#十一、globaleventhandlers-接口-全局事件处理接口" class="header-anchor">#</a> 十一、GlobalEventHandlers 接口 （全局事件处理接口）</h2> <p>指定事件的回调函数，推荐使用的方法是元素的<code>addEventListener</code>方法。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code>div<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'click'</span><span class="token punctuation">,</span> clickHandler<span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><p>除了之外，还有一种方法可以直接指定事件的回调函数。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code>div<span class="token punctuation">.</span>onclick <span class="token operator">=</span> clickHandler<span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><p>这个接口是由<code>GlobalEventHandlers</code>接口提供的。它的优点是使用比较方便，缺点是只能为每个事件指定一个回调函数，并且无法指定事件触发的阶段（捕获阶段还是冒泡阶段）。</p> <p><strong><code>HTMLElement</code>、<code>Document</code>和<code>Window</code>都继承了这个接口，也就是说，各种 HTML 元素、<code>document</code>对象、<code>window</code>对象上面都可以使用<code>GlobalEventHandlers</code>接口提供的属性</strong>。下面就列出这个接口提供的主要的事件属性。</p> <h3 id="_1、globaleventhandlers-onabort-中断事件"><a href="#_1、globaleventhandlers-onabort-中断事件" class="header-anchor">#</a> 1、GlobalEventHandlers.onabort （中断事件）</h3> <p>某个对象的<code>abort</code>事件（停止加载）发生时，就会调用<code>onabort</code>属性指定的回调函数。</p> <p>各种元素的停止加载事件，到底如何触发，目前并没有统一的规定。因此实际上，这个属性现在一般只用在<code>&lt;img&gt;</code>元素上面。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token comment">// HTML 代码如下</span>
<span class="token comment">// &lt;img src=&quot;example.jpg&quot; id=&quot;img&quot;&gt;</span>
<span class="token keyword">var</span> img <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'img'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
img<span class="token punctuation">.</span><span class="token function-variable function">onabort</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'图片加载中断'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br></div></div><h3 id="_2、globaleventhandlers-onerror-错误事件"><a href="#_2、globaleventhandlers-onerror-错误事件" class="header-anchor">#</a> 2、GlobalEventHandlers.onerror （错误事件）</h3> <p><code>error</code>事件发生时，就会调用<code>onerror</code>属性指定的回调函数。</p> <p><code>error</code>事件<strong>分成两种</strong>。</p> <p><strong>一种是 JavaScript 的运行时错误</strong>，这会传到<code>window</code>对象，导致<code>window.onerror()</code>。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code>window<span class="token punctuation">.</span><span class="token function-variable function">onerror</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">message<span class="token punctuation">,</span> source<span class="token punctuation">,</span> lineno<span class="token punctuation">,</span> colno<span class="token punctuation">,</span> error</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment">// ...</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br></div></div><p><code>window.onerror</code>的处理函数共接受五个参数，含义如下。</p> <ul><li>message：错误信息字符串</li> <li>source：报错脚本的 URL</li> <li>lineno：报错的行号，是一个整数</li> <li>colno：报错的列号，是一个整数</li> <li>error： 错误对象</li></ul> <p>另<strong>一种是资源加载错误</strong>，比如<code>&lt;img&gt;</code>或<code>&lt;script&gt;</code>加载的资源出现加载错误。这时，Error 对象会传到对应的元素，导致该元素的<code>onerror</code>属性开始执行。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code>element<span class="token punctuation">.</span><span class="token function-variable function">onerror</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment">// ...</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br></div></div><p>注意，一般来说，资源的加载错误不会触发<code>window.onerror</code>。</p> <h3 id="_3、globaleventhandlers-onload-加载完成事件-、globaleventhandlers-onloadstart-开始加载事件"><a href="#_3、globaleventhandlers-onload-加载完成事件-、globaleventhandlers-onloadstart-开始加载事件" class="header-anchor">#</a> 3、GlobalEventHandlers.onload（加载完成事件）、GlobalEventHandlers.onloadstart（开始加载事件）</h3> <p>元素完成加载时，会触发<code>load</code>事件，执行<code>onload()</code>。它的典型使用场景是<code>window</code>对象和<code>&lt;img&gt;</code>元素。对于<code>window</code>对象来说，只有页面的所有资源加载完成（包括图片、脚本、样式表、字体等所有外部资源），才会触发<code>load</code>事件。</p> <p>对于<code>&lt;img&gt;</code>和<code>&lt;video&gt;</code>等元素，加载开始时还会触发<code>loadstart</code>事件，导致执行<code>onloadstart</code>。</p> <h3 id="_4、globaleventhandlers-onfocus-获取焦点事件-globaleventhandlers-onblur-失去焦点事件"><a href="#_4、globaleventhandlers-onfocus-获取焦点事件-globaleventhandlers-onblur-失去焦点事件" class="header-anchor">#</a> 4、GlobalEventHandlers.onfocus（获取焦点事件），GlobalEventHandlers.onblur（失去焦点事件）</h3> <p>当前元素获得焦点时，会触发<code>element.onfocus</code>；失去焦点时，会触发<code>element.onblur</code>。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code>element<span class="token punctuation">.</span><span class="token function-variable function">onfocus</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">&quot;onfocus event detected!&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
element<span class="token punctuation">.</span><span class="token function-variable function">onblur</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">&quot;onblur event detected!&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br></div></div><p>注意，如果不是可以接受用户输入的元素，要触发<code>onfocus</code>，该元素必须有<code>tabindex</code>属性。</p> <h3 id="_5、globaleventhandlers-onscroll-滚动事件"><a href="#_5、globaleventhandlers-onscroll-滚动事件" class="header-anchor">#</a> 5、GlobalEventHandlers.onscroll（滚动事件）</h3> <p>页面或元素滚动时，会触发<code>scroll</code>事件，导致执行<code>onscroll()</code>。</p> <h3 id="_6、globaleventhandlers-oncontextmenu-右键菜单事件-globaleventhandlers-onshow-显示右键菜单时触发"><a href="#_6、globaleventhandlers-oncontextmenu-右键菜单事件-globaleventhandlers-onshow-显示右键菜单时触发" class="header-anchor">#</a> 6、GlobalEventHandlers.oncontextmenu（右键菜单事件），GlobalEventHandlers.onshow（显示右键菜单时触发）</h3> <p>用户在页面上按下鼠标的右键，会触发<code>contextmenu</code>事件，导致执行<code>oncontextmenu()</code>。如果该属性执行后返回<code>false</code>，就等于禁止了右键菜单。<code>document.oncontextmenu</code>与<code>window.oncontextmenu</code>效果一样。</p> <div class="language-js line-numbers-mode"><pre class="language-js"><code>document<span class="token punctuation">.</span><span class="token function-variable function">oncontextmenu</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token comment">// 禁用右键菜单</span>
  <span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br></div></div><p>上面代码中，<code>oncontextmenu</code>属性执行后返回<code>false</code>，右键菜单就不会出现。</p> <p>元素的右键菜单显示时，会触发该元素的<code>onshow</code>监听函数。</p> <h3 id="_7、其他的事件属性"><a href="#_7、其他的事件属性" class="header-anchor">#</a> 7、其他的事件属性</h3> <p>鼠标的事件属性。</p> <ul><li>onclick</li> <li>ondblclick</li> <li>onmousedown</li> <li>onmouseenter</li> <li>onmouseleave</li> <li>onmousemove</li> <li>onmouseout</li> <li>onmouseover</li> <li>onmouseup</li> <li>onwheel</li></ul> <p>键盘的事件属性。</p> <ul><li>onkeydown</li> <li>onkeypress</li> <li>onkeyup</li></ul> <p>焦点的事件属性。</p> <ul><li>onblur</li> <li>onfocus</li></ul> <p>表单的事件属性。</p> <ul><li>oninput</li> <li>onchange</li> <li>onsubmit</li> <li>onreset</li> <li>oninvalid</li> <li>onselect</li></ul> <p>触摸的事件属性。</p> <ul><li>ontouchcancel</li> <li>ontouchend</li> <li>ontouchmove</li> <li>ontouchstart</li></ul> <p>拖动的事件属性分成两类：一类与被拖动元素相关，另一类与接收被拖动元素的容器元素相关。</p> <p>被拖动元素的事件属性。</p> <ul><li>ondragstart：拖动开始</li> <li>ondrag：拖动过程中，每隔几百毫秒触发一次</li> <li>ondragend：拖动结束</li></ul> <p>接收被拖动元素的容器元素的事件属性。</p> <ul><li>ondragenter：被拖动元素进入容器元素。</li> <li>ondragleave：被拖动元素离开容器元素。</li> <li>ondragover：被拖动元素在容器元素上方，每隔几百毫秒触发一次。</li> <li>ondrop：松开鼠标后，被拖动元素放入容器元素。</li></ul> <p><code>&lt;dialog&gt;</code>对话框元素的事件属性。</p> <ul><li>oncancel</li> <li>onclose</li></ul> <h2 id="文档"><a href="#文档" class="header-anchor">#</a> 文档</h2> <p>学习文档：<a href="https://wangdoc.com/javascript/" target="_blank" rel="noopener noreferrer">https://wangdoc.com/javascript/<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></p></div></div>  <div class="page-edit"><div class="edit-link"><a href="https://github.com/xugaoyi/vuepress-theme-vdoing/edit/master/docs/《JavaScript教程》笔记/06.事件.md" target="_blank" rel="noopener noreferrer">编辑</a> <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></div> <div class="tags"><a href="/blog/tags/?tag=JavaScript" title="标签">#JavaScript</a></div> <div class="last-updated"><span class="prefix">上次更新:</span> <span class="time">2022/01/18, 12:59:48</span></div></div> <div class="page-nav-wapper"><div class="page-nav-centre-wrap"><a href="/blog/pages/7d961b8030c6099e/" class="page-nav-centre page-nav-centre-prev"><div class="tooltip">DOM</div></a> <a href="/blog/pages/bab4930124ad2c10/" class="page-nav-centre page-nav-centre-next"><div class="tooltip">浏览器模型</div></a></div> <div class="page-nav"><p class="inner"><span class="prev">
        ←
        <a href="/blog/pages/7d961b8030c6099e/" class="prev">DOM</a></span> <span class="next"><a href="/blog/pages/bab4930124ad2c10/">浏览器模型</a>→
      </span></p></div></div></div> <div class="article-list"><div class="article-title"><a href="/blog/archives/" class="iconfont icon-bi">最近更新</a></div> <div class="article-wrapper"><dl><dd>01</dd> <dt><a href="/blog/pages/dcebaf/"><div>
            一行代码“黑”掉任意网站
            <span class="title-tag">
              原创
            </span></div></a> <span class="date">11-25</span></dt></dl><dl><dd>02</dd> <dt><a href="/blog/pages/a61298/"><div>
            33个非常实用的JavaScript一行代码
            <!----></div></a> <span class="date">11-02</span></dt></dl><dl><dd>03</dd> <dt><a href="/blog/pages/82baa3/"><div>
            使用State Hook
            <!----></div></a> <span class="date">04-06</span></dt></dl> <dl><dd></dd> <dt><a href="/blog/archives/" class="more">更多文章&gt;</a></dt></dl></div></div></main></div> <div class="footer"><div class="icons"><a href="mailto:894072666@qq.com" title="发邮件" target="_blank" class="iconfont icon-youjian"></a><a href="https://github.com/xugaoyi" title="GitHub" target="_blank" class="iconfont icon-github"></a><a href="https://music.163.com/#/playlist?id=755597173" title="听音乐" target="_blank" class="iconfont icon-erji"></a></div> 
  Theme by
  <a href="https://github.com/xugaoyi/vuepress-theme-vdoing" target="_blank" title="本站主题">Vdoing</a> 
    | Copyright © 2019-2022
    <span>Evan Xu | <a href="https://github.com/xugaoyi/vuepress-theme-vdoing/blob/master/LICENSE" target="_blank">MIT License</a></span></div> <div class="buttons"><div title="返回顶部" class="button blur go-to-top iconfont icon-fanhuidingbu" style="display:none;"></div> <div title="去评论" class="button blur go-to-comment iconfont icon-pinglun" style="display:none;"></div> <div title="主题模式" class="button blur theme-mode-but iconfont icon-zhuti"><ul class="select-box" style="display:none;"><li class="iconfont icon-zidong">
          跟随系统
        </li><li class="iconfont icon-rijianmoshi">
          浅色模式
        </li><li class="iconfont icon-yejianmoshi">
          深色模式
        </li><li class="iconfont icon-yuedu">
          阅读模式
        </li></ul></div></div> <!----> <!----> <!----></div><div class="global-ui"><div></div></div></div>
    <script src="/blog/assets/js/app.aaf1b95a.js" defer></script><script src="/blog/assets/js/2.4e88da26.js" defer></script><script src="/blog/assets/js/137.962a7287.js" defer></script>
  </body>
</html>
